From 68163c09ae1bfd8ebeaabfd21b78650b2ede00df Mon Sep 17 00:00:00 2001 From: Andrey Epin Date: Mon, 19 Dec 2022 09:02:11 -0800 Subject: A base scrollable action row implementation A base implementation of the new scrollable action row; the view is added to the codebase but not used. Bug: 262278109 Test: Tested with some debug code injections (base functionality, a11y, unit tests). Change-Id: Ic109440ce9609e73b72fc86c2cd455c42a421103 --- .../intentresolver/widget/ScrollableActionRow.kt | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 java/src/com/android/intentresolver/widget/ScrollableActionRow.kt (limited to 'java/src') diff --git a/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt new file mode 100644 index 00000000..f3a34985 --- /dev/null +++ b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.android.intentresolver.R + +class ScrollableActionRow : RecyclerView, ActionRow { + constructor(context: Context) : this(context, null) + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + constructor( + context: Context, attrs: AttributeSet?, defStyleAttr: Int + ) : super(context, attrs, defStyleAttr) { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + adapter = Adapter(context) + } + + private val actionsAdapter get() = adapter as Adapter + + override fun setActions(actions: List) { + actionsAdapter.setActions(actions) + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + super.onLayout(changed, l, t, r, b) + setOverScrollMode( + if (areAllChildrenVisible) View.OVER_SCROLL_NEVER else View.OVER_SCROLL_ALWAYS + ) + } + + private val areAllChildrenVisible: Boolean + get() { + val count = getChildCount() + if (count == 0) return true + val first = getChildAt(0) + val last = getChildAt(count - 1) + return getChildAdapterPosition(first) == 0 + && getChildAdapterPosition(last) == actionsAdapter.itemCount - 1 + && isFullyVisible(first) + && isFullyVisible(last) + } + + private fun isFullyVisible(view: View): Boolean = + view.left >= paddingLeft && view.right <= width - paddingRight + + private class Adapter(private val context: Context) : RecyclerView.Adapter() { + private val iconSize: Int = + context.resources.getDimensionPixelSize(R.dimen.chooser_action_view_icon_size) + private val itemLayout = R.layout.chooser_action_view + private var actions: List = emptyList() + + override fun onCreateViewHolder(parent: ViewGroup, type: Int): ViewHolder = + ViewHolder( + LayoutInflater.from(context).inflate(itemLayout, null) as TextView, + iconSize + ) + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(actions[position]) + } + + override fun getItemCount() = actions.size + + override fun onViewRecycled(holder: ViewHolder) { + holder.unbind() + } + + override fun onFailedToRecycleView(holder: ViewHolder): Boolean { + holder.unbind() + return super.onFailedToRecycleView(holder) + } + + fun setActions(actions: List) { + this.actions = ArrayList(actions) + notifyDataSetChanged() + } + } + + private class ViewHolder( + private val view: TextView, private val iconSize: Int + ) : RecyclerView.ViewHolder(view) { + + fun bind(action: ActionRow.Action) { + if (action.icon != null) { + action.icon.setBounds(0, 0, iconSize, iconSize) + view.setCompoundDrawablesRelative(null, action.icon, null, null) + } + view.text = action.label ?: "" + view.setOnClickListener { + action.onClicked.run() + } + view.id = action.id + } + + fun unbind() { + view.setOnClickListener(null) + } + } +} -- cgit v1.2.3-59-g8ed1b