/* * 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.graphics.drawable.Drawable 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 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) { action.icon?.let { icon -> icon.setBounds(0, 0, iconSize, iconSize) // some drawables (edit) does not gets tinted when set to the top of the text // with TextView#setCompoundDrawableRelative tintIcon(icon, view) view.setCompoundDrawablesRelative(null, icon, null, null) } view.text = action.label ?: "" view.setOnClickListener { action.onClicked.run() } view.id = action.id } fun unbind() { view.setOnClickListener(null) } private fun tintIcon(drawable: Drawable, view: TextView) { val tintList = view.compoundDrawableTintList ?: return drawable.setTintList(tintList) view.compoundDrawableTintMode?.let { drawable.setTintMode(it) } view.compoundDrawableTintBlendMode?.let { drawable.setTintBlendMode(it) } } } }