diff options
-rw-r--r-- | java/res/layout/chooser_action_view.xml | 28 | ||||
-rw-r--r-- | java/res/values/dimens.xml | 2 | ||||
-rw-r--r-- | java/src/com/android/intentresolver/widget/ScrollableActionRow.kt | 120 |
3 files changed, 150 insertions, 0 deletions
diff --git a/java/res/layout/chooser_action_view.xml b/java/res/layout/chooser_action_view.xml new file mode 100644 index 00000000..d74798e2 --- /dev/null +++ b/java/res/layout/chooser_action_view.xml @@ -0,0 +1,28 @@ +<!-- + ~ Copyright (C) 2019 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 + --> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center" + android:drawablePadding="8dp" + android:textColor="?android:attr/textColorPrimary" + android:textSize="12sp" + android:maxWidth="192dp" + android:singleLine="true" + android:clickable="true" + android:drawableTint="?android:attr/textColorPrimary" + android:drawableTintMode="src_in" + style="?android:attr/borderlessButtonStyle" + /> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index 2d6fe816..93cb4637 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -50,4 +50,6 @@ <dimen name="resolver_profile_tab_margin">4dp</dimen> <dimen name="chooser_action_button_icon_size">18dp</dimen> + <dimen name="chooser_action_view_icon_size">22dp</dimen> + <dimen name="chooser_action_margin">0dp</dimen> </resources> 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<ActionRow.Action>) { + 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<ViewHolder>() { + 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<ActionRow.Action> = 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<ActionRow.Action>) { + 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) + } + } +} |