commit 9850b230e46bad164d2177274bd7acf01a6710fb from: darkwolf date: Sun Jul 19 00:49:56 2026 UTC DiscoverFragment in Kotlin commit - 130ae87d331eb8c061d0a6230ce69e11c49759b4 commit + 9850b230e46bad164d2177274bd7acf01a6710fb blob - 4c72a314224c3ece3cf4df2cff26c9833c6a0a7e (mode 644) blob + /dev/null --- mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java +++ /dev/null @@ -1,342 +0,0 @@ -package org.joinmastodon.android.fragments.discover; - -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.app.assist.AssistContent; -import android.os.Build; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.joinmastodon.android.GlobalUserPreferences; -import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSessionManager; -import org.joinmastodon.android.fragments.IsOnTop; -import org.joinmastodon.android.fragments.ScrollableToTop; -import org.joinmastodon.android.model.Instance; -import org.joinmastodon.android.model.SearchResult; -import org.joinmastodon.android.ui.OutlineProviders; -import org.joinmastodon.android.ui.SimpleViewHolder; -import org.joinmastodon.android.ui.tabs.TabLayout; -import org.joinmastodon.android.ui.tabs.TabLayoutMediator; -import org.joinmastodon.android.ui.utils.UiUtils; -import org.joinmastodon.android.utils.ProvidesAssistContent; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; -import androidx.viewpager2.widget.ViewPager2; - -import java.util.Optional; - -import me.grishka.appkit.Nav; -import me.grishka.appkit.fragments.AppKitFragment; -import me.grishka.appkit.fragments.BaseRecyclerFragment; -import me.grishka.appkit.fragments.OnBackPressedListener; -import me.grishka.appkit.utils.V; - -public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, IsOnTop, ProvidesAssistContent{ - private static final int QUERY_RESULT=937; - - private TabLayout tabLayout; - private ViewPager2 pager; - private FrameLayout[] tabViews; - private TabLayoutMediator tabLayoutMediator; - private boolean searchActive; - private FrameLayout searchView; - private ImageButton searchBack; - private TextView searchText; - private View tabsDivider; - - private DiscoverPostsFragment postsFragment; - private TrendingHashtagsFragment hashtagsFragment; - private DiscoverNewsFragment newsFragment; - private DiscoverAccountsFragment accountsFragment; - private SearchFragment searchFragment; - - private String accountID; - private String currentQuery; - - private boolean disableDiscover; - private boolean isIceshrimp; - - @Override - public void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); - if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) - setRetainInstance(true); - - accountID=getArguments().getString("account"); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){ - LinearLayout view=(LinearLayout) inflater.inflate(R.layout.fragment_discover, container, false); - - tabLayout=view.findViewById(R.id.tabbar); - pager=view.findViewById(R.id.pager); - - Optional instance=AccountSessionManager.get(accountID).getInstance(); - disableDiscover=instance.map(Instance::isAkkoma).orElse(false) || instance.map(Instance::isMitra).orElse(false); - isIceshrimp=instance.map(Instance::isIceshrimp).orElse(false); - - tabViews=new FrameLayout[isIceshrimp ? 3 : 4]; // reduce array size on Iceshrimp to hide news feed because it's unsupported and always returns an empty list - for(int i=0;i R.id.discover_posts; - case 1 -> R.id.discover_hashtags; - case 2 -> isIceshrimp ? R.id.discover_users : R.id.discover_news; // skip unsupported news discovery on Iceshrimp - case 3 -> R.id.discover_users; - default -> throw new IllegalStateException("Unexpected value: "+i); - }); - tabView.setVisibility(View.GONE); - view.addView(tabView); // needed so the fragment manager will have somewhere to restore the tab fragment - tabViews[i]=tabView; - } - - tabLayout.setTabTextColors(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSurfaceVariant), UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary)); - tabLayout.setTabTextSize(V.dp(14)); - - pager.setOffscreenPageLimit(4); - pager.setAdapter(new DiscoverPagerAdapter()); - pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){ - @Override - public void onPageSelected(int position){ - Fragment _page=getFragmentForPage(position); - if(_page instanceof BaseRecyclerFragment page){ - if(!page.loaded && !page.isDataLoading()) - page.loadData(); - } - } - }); - - if(hashtagsFragment==null){ - Bundle args=new Bundle(); - args.putString("account", accountID); - args.putBoolean("__is_tab", true); - - postsFragment=new DiscoverPostsFragment(); - postsFragment.setArguments(args); - - hashtagsFragment=new TrendingHashtagsFragment(); - hashtagsFragment.setArguments(args); - - newsFragment=new DiscoverNewsFragment(); - newsFragment.setArguments(args); - - accountsFragment=new DiscoverAccountsFragment(); - accountsFragment.setArguments(args); - - FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); - transaction - .add(R.id.discover_posts, postsFragment) - .add(R.id.discover_hashtags, hashtagsFragment); - if(!isIceshrimp) // skip unsupported news discovery on Iceshrimp - transaction.add(R.id.discover_news, newsFragment); - transaction - .add(R.id.discover_users, accountsFragment) - .commit(); - } - - tabLayoutMediator=new TabLayoutMediator(tabLayout, pager, new TabLayoutMediator.TabConfigurationStrategy(){ - @Override - public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){ - tab.setText(switch(position){ - case 0 -> R.string.posts; - case 1 -> R.string.hashtags; - case 2 -> isIceshrimp ? R.string.for_you : R.string.news; // skip unsupported news discovery on Iceshrimp - case 3 -> R.string.for_you; - default -> throw new IllegalStateException("Unexpected value: "+position); - }); - } - }); - tabLayoutMediator.attach(); - tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){ - @Override - public void onTabSelected(TabLayout.Tab tab){} - - @Override - public void onTabUnselected(TabLayout.Tab tab){} - - @Override - public void onTabReselected(TabLayout.Tab tab){ - scrollToTop(); - } - }); - - searchView=view.findViewById(R.id.search_fragment); - if(searchFragment==null){ - searchFragment=new SearchFragment(); - Bundle args=new Bundle(); - args.putString("account", accountID); - searchFragment.setArguments(args); - getChildFragmentManager().beginTransaction().add(R.id.search_fragment, searchFragment).commit(); - } - - searchBack=view.findViewById(R.id.search_back); - searchText=view.findViewById(R.id.search_text); - searchBack.setImportantForAccessibility(searchActive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES : View.IMPORTANT_FOR_ACCESSIBILITY_NO); - searchBack.setOnClickListener(v->{ - if(searchActive) exitSearch(); else openSearch(); - }); - if(searchActive) searchBack.setImageResource(R.drawable.ic_fluent_arrow_left_24_regular); - else searchBack.setEnabled(false); - if(searchActive || disableDiscover){ - pager.setVisibility(View.GONE); - tabLayout.setVisibility(View.GONE); - searchView.setVisibility(View.VISIBLE); - } - - View searchWrap=view.findViewById(R.id.search_wrap); - searchWrap.setOutlineProvider(OutlineProviders.roundedRect(28)); - searchWrap.setClipToOutline(true); - searchText.setOnClickListener(v->openSearch()); - tabsDivider=view.findViewById(R.id.tabs_divider); - - return view; - } - - @Override - public boolean isOnTop() { - return searchActive ? searchFragment.isOnTop() - : ((IsOnTop)getFragmentForPage(pager.getCurrentItem())).isOnTop(); - } - - public void openSearch() { - Bundle args=new Bundle(); - args.putString("account", accountID); - if(!TextUtils.isEmpty(currentQuery)){ - args.putString("query", currentQuery); - } - Nav.goForResult(getActivity(), SearchQueryFragment.class, args, QUERY_RESULT, DiscoverFragment.this); - } - - @Override - public void scrollToTop(){ - if(!searchActive){ - if (((IsOnTop)getFragmentForPage(pager.getCurrentItem())).isOnTop() && GlobalUserPreferences.doubleTapToSwipe){ - int nextPage=(pager.getCurrentItem()+1)%tabViews.length; - pager.setCurrentItem(nextPage, true); - return; - } - ((ScrollableToTop)getFragmentForPage(pager.getCurrentItem())).scrollToTop(); - }else{ - searchFragment.scrollToTop(); - } - } - - public void loadData(){ - if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading) - hashtagsFragment.loadData(); - } - - private void enterSearch(){ - if(!searchActive){ - searchActive=true; - pager.setVisibility(View.GONE); - tabLayout.setVisibility(View.GONE); - searchView.setVisibility(View.VISIBLE); - searchBack.setImageResource(R.drawable.ic_fluent_arrow_left_24_regular); - searchBack.setEnabled(true); - searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - tabsDivider.setVisibility(View.GONE); - } - } - - private void exitSearch(){ - if(!searchActive) - return; - searchActive=false; - searchText.setText(R.string.sk_search_fediverse); - searchBack.setImageResource(R.drawable.ic_fluent_search_24_regular); - searchBack.setEnabled(false); - searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - currentQuery=null; - searchFragment.clear(); - - if(disableDiscover) return; - pager.setVisibility(View.VISIBLE); - tabLayout.setVisibility(View.VISIBLE); - searchView.setVisibility(View.GONE); - tabsDivider.setVisibility(View.VISIBLE); - } - - private Fragment getFragmentForPage(int page){ - return switch(page){ - case 0 -> postsFragment; - case 1 -> hashtagsFragment; - case 2 -> isIceshrimp ? accountsFragment : newsFragment; // skip unsupported news discovery on Iceshrimp - case 3 -> accountsFragment; - default -> throw new IllegalStateException("Unexpected value: "+page); - }; - } - - @Override - public boolean onBackPressed(){ - if(searchActive){ - exitSearch(); - return true; - } - return false; - } - - @Override - public void onFragmentResult(int reqCode, boolean success, Bundle result){ - if(reqCode==QUERY_RESULT && success){ - enterSearch(); - currentQuery=result.getString("query"); - SearchResult.Type type; - if(result.containsKey("filter")){ - type=SearchResult.Type.values()[result.getInt("filter")]; - }else{ - type=null; - } - searchFragment.setQuery(currentQuery, type); - searchText.setText(currentQuery); - } - } - - @Override - public void onProvideAssistContent(AssistContent assistContent) { - callFragmentToProvideAssistContent(searchActive - ? searchFragment - : getFragmentForPage(pager.getCurrentItem()), assistContent); - } - - private class DiscoverPagerAdapter extends RecyclerView.Adapter{ - @NonNull - @Override - public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ - FrameLayout view=new FrameLayout(parent.getContext()); - view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - return new SimpleViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){ - FrameLayout view=tabViews[position]; - if(view.getParent() instanceof ViewGroup parent) - parent.removeView(view); - view.setVisibility(View.VISIBLE); - ((FrameLayout)holder.itemView).addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - - @Override - public int getItemCount(){ - return tabViews.length; - } - - @Override - public int getItemViewType(int position){ - return position; - } - } -} blob - /dev/null blob + 725fc71938f6c832426f9a9f0070014bd96fc1d9 (mode 644) --- /dev/null +++ mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.kt @@ -0,0 +1,325 @@ +package org.joinmastodon.android.fragments.discover + +import android.app.Fragment +import android.app.assist.AssistContent +import android.os.Build +import android.os.Bundle +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageButton +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import me.grishka.appkit.Nav +import me.grishka.appkit.fragments.AppKitFragment +import me.grishka.appkit.fragments.BaseRecyclerFragment +import me.grishka.appkit.fragments.OnBackPressedListener +import me.grishka.appkit.utils.V +import org.joinmastodon.android.GlobalUserPreferences +import org.joinmastodon.android.R +import org.joinmastodon.android.api.session.AccountSessionManager +import org.joinmastodon.android.fragments.IsOnTop +import org.joinmastodon.android.fragments.ScrollableToTop +import org.joinmastodon.android.model.Instance +import org.joinmastodon.android.model.SearchResult +import org.joinmastodon.android.ui.OutlineProviders +import org.joinmastodon.android.ui.SimpleViewHolder +import org.joinmastodon.android.ui.tabs.TabLayout +import org.joinmastodon.android.ui.tabs.TabLayoutMediator +import org.joinmastodon.android.ui.utils.UiUtils +import org.joinmastodon.android.utils.ProvidesAssistContent + +const val QUERY_RESULT: Int = 937 + +class DiscoverFragment : AppKitFragment(), ScrollableToTop, OnBackPressedListener, IsOnTop, ProvidesAssistContent { + + private lateinit var tabLayout: TabLayout + private lateinit var pager: ViewPager2 + private lateinit var tabViews: Array + private lateinit var tabLayoutMediator: TabLayoutMediator + + private lateinit var searchView: FrameLayout + + private lateinit var searchBack: ImageButton + private lateinit var searchText: TextView + private lateinit var tabsDivider: View + + private var hashtagsFragment: TrendingHashtagsFragment? = null + private var postsFragment: DiscoverPostsFragment? = null + + private var newsFragment: DiscoverNewsFragment? = null + + private var accountsFragment: DiscoverAccountsFragment? = null + private var searchFragment: SearchFragment? = null + private var disableDiscover: Boolean = false + private var isIceshrimp: Boolean = false + private var isSearchActive: Boolean = false + private var accountID: String? = null + private var currentQuery: String? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + retainInstance = true + accountID = arguments.getString("account") + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val view: LinearLayout = inflater.inflate(R.layout.fragment_discover, container, false) as LinearLayout + + tabLayout = view.findViewById(R.id.tabbar) + pager = view.findViewById(R.id.pager) + + val instance = AccountSessionManager.get(accountID).instance + disableDiscover = instance.map { instance: Instance -> (instance.isAkkoma || instance.isMitra) }.orElse(false) + isIceshrimp = instance.map { instance: Instance -> instance.isIceshrimp }.orElse(false) + + tabViews = arrayOfNulls(4) as Array + + for (i in tabViews.indices) { + val tabView = FrameLayout(activity) + tabView.id = when (i) { + 0 -> R.id.discover_posts + 1 -> R.id.discover_hashtags + 2 -> if (isIceshrimp) R.id.discover_users else R.id.discover_news + 3 -> R.id.discover_users + else -> throw IllegalStateException("Unexpected value: $i") + } + tabView.visibility = View.GONE + view.addView(tabView) // needed so the fragment manager will have somewhere to restore the tab fragment + tabViews[i] = tabView + } + + tabLayout.setTabTextColors(UiUtils.getThemeColor(activity, R.attr.colorM3OnSurfaceVariant), UiUtils.getThemeColor(activity, R.attr.colorM3Primary)); + tabLayout.setTabTextSize(V.dp(14F).toFloat()); + + pager.offscreenPageLimit = 4 + pager.adapter = DiscoverPagerAdapter() + pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + val page = getFragmentForPage(position) + page.let { + if (it is BaseRecyclerFragment<*>) { + if (!it.loaded && !it.isDataLoading) + it.loadData() + } + } + } + }) + + if (hashtagsFragment == null) { + val args = Bundle() + args.putString("account", accountID) + args.putBoolean("__is_tab", true) + + postsFragment = DiscoverPostsFragment() + postsFragment?.arguments = args + + hashtagsFragment = TrendingHashtagsFragment() + hashtagsFragment?.arguments = args + + newsFragment = DiscoverNewsFragment() + newsFragment?.arguments = args + + accountsFragment = DiscoverAccountsFragment() + accountsFragment?.arguments = args + + val transaction = childFragmentManager.beginTransaction() + transaction.add(R.id.discover_posts, postsFragment) + .add(R.id.discover_hashtags, hashtagsFragment) + + if (!isIceshrimp) + transaction.add(R.id.discover_news, newsFragment) + + transaction.add(R.id.discover_users, accountsFragment).commit() + } + + tabLayoutMediator = TabLayoutMediator(tabLayout, pager) { tab, position -> + tab.setText( + when (position) { + 0 -> R.string.posts + 1 -> R.string.hashtags + 2 -> if (isIceshrimp) R.string.for_you else R.string.news + 3 -> R.string.for_you + else -> throw IllegalStateException("Unexpected value: $position") + } + ) + } + + tabLayoutMediator.attach() + tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?) {} + + override fun onTabUnselected(tab: TabLayout.Tab?) {} + + override fun onTabReselected(tab: TabLayout.Tab?) { + scrollToTop() + } + + }) + + searchView = view.findViewById(R.id.search_fragment) + if (searchFragment == null) { + searchFragment = SearchFragment() + val args = Bundle() + args.putString("account", accountID) + searchFragment?.arguments = args + childFragmentManager.beginTransaction().add(R.id.search_fragment, searchFragment).commit() + } + + searchBack = view.findViewById(R.id.search_back) + searchText = view.findViewById(R.id.search_text) + searchBack.setImportantForAccessibility(if (isSearchActive) View.IMPORTANT_FOR_ACCESSIBILITY_YES else View.IMPORTANT_FOR_ACCESSIBILITY_NO) + searchBack.setOnClickListener { if (isSearchActive) exitSearch() else openSearch() } + if (isSearchActive) searchBack.setImageResource(R.drawable.ic_fluent_arrow_left_24_regular) + else searchBack.isEnabled = false + if (isSearchActive || disableDiscover) { + pager.visibility = View.GONE + tabLayout.visibility = View.GONE + searchView.visibility = View.VISIBLE + } + + val searchWrap: View = view.findViewById(R.id.search_wrap) + searchWrap.outlineProvider = OutlineProviders.roundedRect(28) + searchWrap.clipToOutline = true + searchText.setOnClickListener { _ -> openSearch() } + tabsDivider = view.findViewById(R.id.tabs_divider) + + return view + } + + private fun getFragmentForPage(page: Int): Fragment? { + return when (page) { + 0 -> postsFragment + 1 -> hashtagsFragment + 2 -> if (isIceshrimp) accountsFragment else newsFragment + 3 -> accountsFragment + else -> throw java.lang.IllegalStateException("Unexpected value: $page") + } + } + + override fun isOnTop(): Boolean { + return if (isSearchActive) + searchFragment!!.isOnTop + else + (getFragmentForPage(pager.currentItem) as IsOnTop).isOnTop() + } + + fun openSearch() { + val args = Bundle() + args.putString("account", accountID) + if (!TextUtils.isEmpty(currentQuery)) { + args.putString("query", currentQuery) + } + Nav.goForResult(activity, SearchQueryFragment::class.java, args, QUERY_RESULT, this@DiscoverFragment) + } + + override fun onBackPressed(): Boolean { + if (isSearchActive) { + exitSearch() + return true + } + return false + } + + override fun onFragmentResult(reqCode: Int, success: Boolean, result: Bundle?) { + if (reqCode === QUERY_RESULT && success) { + enterSearch() + currentQuery = result!!.getString("query") + val type: SearchResult.Type? = if (result.containsKey("filter")) { + SearchResult.Type.entries[result.getInt("filter")] + } else { + null + } + searchFragment!!.setQuery(currentQuery, type) + searchText.text = currentQuery + } + } + + override fun onProvideAssistContent(assistContent: AssistContent?) { + callFragmentToProvideAssistContent( + if (isSearchActive) + searchFragment + else + getFragmentForPage(pager.currentItem), assistContent + ) + } + + override fun scrollToTop() { + if (!isSearchActive) { + if ((getFragmentForPage(pager.currentItem) as IsOnTop).isOnTop() && GlobalUserPreferences.doubleTapToSwipe) { + val nextPage = (pager.currentItem + 1) % tabViews.size + pager.setCurrentItem(nextPage, true) + return + } + (getFragmentForPage(pager.currentItem) as ScrollableToTop).scrollToTop() + } else { + searchFragment?.scrollToTop() + } + } + + fun loadData() { + if (hashtagsFragment != null) + hashtagsFragment?.let { if (!it.loaded && !it.dataLoading) it.loadData() } + } + + private fun enterSearch() { + if (!isSearchActive) { + isSearchActive = true + pager.visibility = View.GONE + tabLayout.visibility = View.GONE + searchView.visibility = View.VISIBLE + searchBack.setImageResource(R.drawable.ic_fluent_arrow_left_24_regular) + searchBack.isEnabled = true + searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES) + tabsDivider.visibility = View.GONE + } + } + + private fun exitSearch() { + if (!isSearchActive) + return + isSearchActive = false + searchText.setText(R.string.sk_search_fediverse) + searchBack.setImageResource(R.drawable.ic_fluent_search_24_regular) + searchBack.isEnabled = false + searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO) + currentQuery = null + searchFragment?.clear() + + if (disableDiscover) return + pager.visibility = View.VISIBLE + tabLayout.visibility = View.VISIBLE + searchView.visibility = View.GONE + tabsDivider.visibility = View.VISIBLE + + } + + private inner class DiscoverPagerAdapter : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder { + val view = FrameLayout(parent.context) + view.layoutParams = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + return SimpleViewHolder(view) + } + + override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) { + val view = tabViews[position] + view.parent.let { + if (it is ViewGroup) { + it.removeView(view) + } + } + view.visibility = View.VISIBLE + (holder.itemView as FrameLayout).addView(view, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) + } + + override fun getItemCount(): Int = tabViews.size + + override fun getItemViewType(position: Int) = position + + } +} \ No newline at end of file