diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/activity/FeatureOverviewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/activity/FeatureOverviewActivity.kt index eb1d63f0d..cb0b8c337 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/activity/FeatureOverviewActivity.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/activity/FeatureOverviewActivity.kt @@ -33,7 +33,7 @@ import java.util.* * */ class FeatureOverviewActivity : AppCompatActivity() { - private var recyclerView: RecyclerView? = null + private lateinit var recyclerView: RecyclerView private var sectionAdapter: FeatureSectionAdapter? = null private var features: List? = null @@ -42,17 +42,20 @@ class FeatureOverviewActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_feature_overview) recyclerView = findViewById(R.id.recyclerView) as RecyclerView - recyclerView!!.layoutManager = LinearLayoutManager(this) - recyclerView!!.addOnItemTouchListener(SimpleOnItemTouchListener()) - recyclerView!!.setHasFixedSize(true) + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.addOnItemTouchListener(SimpleOnItemTouchListener()) + recyclerView.setHasFixedSize(true) + ItemClickSupport.addTo(recyclerView) - .setOnItemClickListener { recyclerView: RecyclerView?, position: Int, view: View? -> - if (!sectionAdapter!!.isSectionHeaderPosition(position)) { - val itemPosition = sectionAdapter!!.getConvertedPosition(position) - val feature = features!![itemPosition] - startFeature(feature) + .setOnItemClickListener(object : ItemClickSupport.OnItemClickListener { + override fun onItemClicked(recyclerView: RecyclerView?, position: Int, view: View?) { + if (sectionAdapter!!.isSectionHeaderPosition(position).not()) { + val itemPosition = sectionAdapter!!.getConvertedPosition(position) + val feature = features!![itemPosition] + startFeature(feature) + } } - } + }) if (savedInstanceState == null) { loadFeatures() } else { @@ -164,7 +167,6 @@ class FeatureOverviewActivity : AppCompatActivity() { onFeaturesLoaded(features) } } - companion object { private const val KEY_STATE_FEATURES = "featureList" } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.java deleted file mode 100644 index fc8dc64b3..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.maplibre.android.testapp.adapter; - -import android.content.Context; -import android.util.SparseArray; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.IdRes; -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import org.maplibre.android.testapp.utils.FontCache; - -import java.util.Arrays; - -public class FeatureSectionAdapter extends RecyclerView.Adapter { - - private static final int SECTION_TYPE = 0; - - private final Context context; - private final SparseArray
sections; - private final RecyclerView.Adapter adapter; - - @LayoutRes - private final int sectionRes; - - @IdRes - private final int textRes; - - private boolean valid = true; - - public FeatureSectionAdapter(Context ctx, int sectionResourceId, int textResourceId, - RecyclerView.Adapter baseAdapter) { - context = ctx; - sectionRes = sectionResourceId; - textRes = textResourceId; - adapter = baseAdapter; - sections = new SparseArray<>(); - adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - valid = adapter.getItemCount() > 0; - notifyDataSetChanged(); - } - - @Override - public void onItemRangeChanged(int positionStart, int itemCount) { - valid = adapter.getItemCount() > 0; - notifyItemRangeChanged(positionStart, itemCount); - } - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) { - valid = adapter.getItemCount() > 0; - notifyItemRangeInserted(positionStart, itemCount); - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) { - valid = adapter.getItemCount() > 0; - notifyItemRangeRemoved(positionStart, itemCount); - } - }); - } - - - public static class SectionViewHolder extends RecyclerView.ViewHolder { - - public TextView title; - - public SectionViewHolder(@NonNull View view, @IdRes int textRes) { - super(view); - title = (TextView) view.findViewById(textRes); - title.setTypeface(FontCache.get("Roboto-Medium.ttf", view.getContext())); - } - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) { - if (typeView == SECTION_TYPE) { - final View view = LayoutInflater.from(context).inflate(sectionRes, parent, false); - return new SectionViewHolder(view, textRes); - } else { - return adapter.onCreateViewHolder(parent, typeView - 1); - } - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) { - if (isSectionHeaderPosition(position)) { - String cleanTitle = sections.get(position).title.toString().replace("_", " "); - ((SectionViewHolder) sectionViewHolder).title.setText(cleanTitle); - } else { - adapter.onBindViewHolder(sectionViewHolder, getConvertedPosition(position)); - } - - } - - @Override - public int getItemViewType(int position) { - return isSectionHeaderPosition(position) - ? SECTION_TYPE - : adapter.getItemViewType(getConvertedPosition(position)) + 1; - } - - - public static class Section { - int firstPosition; - int sectionedPosition; - CharSequence title; - - public Section(int firstPosition, CharSequence title) { - this.firstPosition = firstPosition; - this.title = title; - } - - public CharSequence getTitle() { - return title; - } - } - - - public void setSections(Section[] sections) { - this.sections.clear(); - - Arrays.sort(sections, (section, section1) -> (section.firstPosition == section1.firstPosition) - ? 0 - : ((section.firstPosition < section1.firstPosition) ? -1 : 1)); - - int offset = 0; - for (Section section : sections) { - section.sectionedPosition = section.firstPosition + offset; - this.sections.append(section.sectionedPosition, section); - ++offset; - } - - notifyDataSetChanged(); - } - - public int getConvertedPosition(int sectionedPosition) { - if (isSectionHeaderPosition(sectionedPosition)) { - return RecyclerView.NO_POSITION; - } - - int offset = 0; - for (int i = 0; i < sections.size(); i++) { - if (sections.valueAt(i).sectionedPosition > sectionedPosition) { - break; - } - --offset; - } - return sectionedPosition + offset; - } - - public boolean isSectionHeaderPosition(int position) { - return sections.get(position) != null; - } - - - @Override - public long getItemId(int position) { - return isSectionHeaderPosition(position) - ? Integer.MAX_VALUE - sections.indexOfKey(position) - : adapter.getItemId(getConvertedPosition(position)); - } - - @Override - public int getItemCount() { - return (valid ? adapter.getItemCount() + sections.size() : 0); - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.kt new file mode 100644 index 000000000..3a19cae17 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/adapter/FeatureSectionAdapter.kt @@ -0,0 +1,142 @@ +package org.maplibre.android.testapp.adapter + +import android.content.Context +import android.util.SparseArray +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.annotation.IdRes +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.RecyclerView +import org.maplibre.android.testapp.utils.FontCache +import java.util.* + +class FeatureSectionAdapter( + private val context: Context, + @param:LayoutRes private val sectionRes: Int, + @param:IdRes private val textRes: Int, + private val adapter: FeatureAdapter +) : RecyclerView.Adapter() { + + private val sections = SparseArray
() + private var valid = true + + private val adapterDataObserver: RecyclerView.AdapterDataObserver = + object : RecyclerView.AdapterDataObserver() { + override fun onChanged() { + valid = adapter.itemCount > 0 + notifyDataSetChanged() + } + + override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { + valid = adapter.itemCount > 0 + notifyItemRangeChanged(positionStart, itemCount) + } + + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + valid = adapter.itemCount > 0 + notifyItemRangeInserted(positionStart, itemCount) + } + + override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { + valid = adapter.itemCount > 0 + notifyItemRangeRemoved(positionStart, itemCount) + } + } + + init { + adapter.registerAdapterDataObserver(adapterDataObserver) + } + + override fun onCreateViewHolder(parent: ViewGroup, typeView: Int): RecyclerView.ViewHolder { + return if (typeView == SECTION_TYPE) { + val view = LayoutInflater.from(context).inflate(sectionRes, parent, false) + SectionViewHolder(view, textRes) + } else { + adapter.onCreateViewHolder(parent, typeView - 1) + } + } + + override fun onBindViewHolder(sectionViewHolder: RecyclerView.ViewHolder, position: Int) { + if (isSectionHeaderPosition(position)) { + val cleanTitle = sections.get(position).title.toString().replace("_", " ") + (sectionViewHolder as SectionViewHolder).title.text = cleanTitle + } else { + adapter.onBindViewHolder(sectionViewHolder as FeatureAdapter.ViewHolder, getConvertedPosition(position)) + } + } + + override fun getItemViewType(position: Int): Int { + return if (isSectionHeaderPosition(position)) { + SECTION_TYPE + } else { + adapter.getItemViewType(getConvertedPosition(position)) + 1 + } + } + + override fun getItemId(position: Int): Long { + return if (isSectionHeaderPosition(position)) { + Integer.MAX_VALUE - sections.indexOfKey(position).toLong() + } else { + adapter.getItemId(getConvertedPosition(position)) + } + } + + override fun getItemCount(): Int { + return if (valid) adapter.itemCount + sections.size() else 0 + } + + fun setSections(sections: Array
) { + this.sections.clear() + Arrays.sort(sections) { section, section1 -> + if (section.firstPosition == section1.firstPosition) { + 0 + } else if (section.firstPosition < section1.firstPosition) { + -1 + } else { + 1 + } + } + for ((offset, section) in sections.withIndex()) { + section.sectionedPosition = section.firstPosition + offset + this.sections.append(section.sectionedPosition, section) + } + notifyDataSetChanged() + } + + fun getConvertedPosition(sectionedPosition: Int): Int { + if (isSectionHeaderPosition(sectionedPosition)) { + return RecyclerView.NO_POSITION + } + var offset = 0 + for (i in 0 until sections.size()) { + if (sections.valueAt(i).sectionedPosition > sectionedPosition) { + break + } + --offset + } + return sectionedPosition + offset + } + + fun isSectionHeaderPosition(position: Int): Boolean { + return sections.get(position) != null + } + + class SectionViewHolder(view: View, textRes: Int) : + RecyclerView.ViewHolder(view) { + val title: TextView = view.findViewById(textRes) + + init { + title.typeface = FontCache["Roboto-Medium.ttf", view.context] + } + } + + class Section(val firstPosition: Int, val title: CharSequence) { + var sectionedPosition = 0 + } + + companion object { + private const val SECTION_TYPE = 0 + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.java deleted file mode 100644 index 89e239a8c..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.maplibre.android.testapp.utils; - -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -import org.maplibre.android.testapp.R; - -public class ItemClickSupport { - private final RecyclerView recyclerView; - private OnItemClickListener onItemClickListener; - private OnItemLongClickListener onItemLongClickListener; - private View.OnClickListener onClickListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - if (onItemClickListener != null) { - RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view); - onItemClickListener.onItemClicked(recyclerView, holder.getAdapterPosition(), view); - } - } - }; - private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - if (onItemLongClickListener != null) { - RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view); - return onItemLongClickListener.onItemLongClicked(recyclerView, holder.getAdapterPosition(), view); - } - return false; - } - }; - private RecyclerView.OnChildAttachStateChangeListener attachListener - = new RecyclerView.OnChildAttachStateChangeListener() { - @Override - public void onChildViewAttachedToWindow(View view) { - if (onItemClickListener != null) { - view.setOnClickListener(onClickListener); - } - if (onItemLongClickListener != null) { - view.setOnLongClickListener(onLongClickListener); - } - } - - @Override - public void onChildViewDetachedFromWindow(View view) { - - } - }; - - private ItemClickSupport(RecyclerView recyclerView) { - this.recyclerView = recyclerView; - this.recyclerView.setTag(R.id.item_click_support, this); - this.recyclerView.addOnChildAttachStateChangeListener(attachListener); - } - - public static ItemClickSupport addTo(RecyclerView view) { - ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); - if (support == null) { - support = new ItemClickSupport(view); - } - return support; - } - - public static ItemClickSupport removeFrom(RecyclerView view) { - ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); - if (support != null) { - support.detach(view); - } - return support; - } - - public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) { - onItemClickListener = listener; - return this; - } - - public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) { - onItemLongClickListener = listener; - return this; - } - - private void detach(RecyclerView view) { - view.removeOnChildAttachStateChangeListener(attachListener); - view.setTag(R.id.item_click_support, null); - } - - public interface OnItemClickListener { - - void onItemClicked(RecyclerView recyclerView, int position, View view); - } - - public interface OnItemLongClickListener { - - boolean onItemLongClicked(RecyclerView recyclerView, int position, View view); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.kt new file mode 100644 index 000000000..f7170f489 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/org/maplibre/android/testapp/utils/ItemClickSupport.kt @@ -0,0 +1,78 @@ +package org.maplibre.android.testapp.utils + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import org.maplibre.android.testapp.R + +class ItemClickSupport private constructor(private val recyclerView: RecyclerView) { + private var onItemClickListener: OnItemClickListener? = null + private var onItemLongClickListener: OnItemLongClickListener? = null + private val onClickListener = View.OnClickListener { view -> + onItemClickListener?.let { + val holder = recyclerView.getChildViewHolder(view) + it.onItemClicked(recyclerView, holder.adapterPosition, view) + } + } + private val onLongClickListener = View.OnLongClickListener { view -> + onItemLongClickListener?.let { + val holder = recyclerView.getChildViewHolder(view) + it.onItemLongClicked(recyclerView, holder.adapterPosition, view) + } + false + } + private val attachListener = object : RecyclerView.OnChildAttachStateChangeListener { + override fun onChildViewAttachedToWindow(view: View) { + onItemClickListener?.let { + view.setOnClickListener(onClickListener) + } + onItemLongClickListener?.let { + view.setOnLongClickListener(onLongClickListener) + } + } + + override fun onChildViewDetachedFromWindow(view: View) {} + } + + fun setOnItemClickListener(listener: OnItemClickListener?): ItemClickSupport { + onItemClickListener = listener + return this + } + + fun setOnItemLongClickListener(listener: OnItemLongClickListener?): ItemClickSupport { + onItemLongClickListener = listener + return this + } + + private fun detach(view: RecyclerView) { + view.removeOnChildAttachStateChangeListener(attachListener) + view.setTag(R.id.item_click_support, null) + } + + companion object { + fun addTo(view: RecyclerView): ItemClickSupport { + var support = view.getTag(R.id.item_click_support) as ItemClickSupport? + if (support == null) { + support = ItemClickSupport(view) + view.setTag(R.id.item_click_support, support) + view.addOnChildAttachStateChangeListener(support.attachListener) + } + return support + } + + fun removeFrom(view: RecyclerView): ItemClickSupport? { + val support = view.getTag(R.id.item_click_support) as ItemClickSupport? + support?.let { + it.detach(view) + } + return support + } + } + + interface OnItemClickListener { + fun onItemClicked(recyclerView: RecyclerView?, position: Int, view: View?) + } + + interface OnItemLongClickListener { + fun onItemLongClicked(recyclerView: RecyclerView?, position: Int, view: View?): Boolean + } +}