// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.keyboard_accessory.sheet_tabs;
import static org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabProperties.IS_DEFAULT_A11Y_FOCUS_REQUESTED;
import static org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabProperties.ITEMS;
import static org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabProperties.SCROLL_LISTENER;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.chromium.chrome.browser.keyboard_accessory.R;
import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabItemsModel.AccessorySheetDataPiece;
import org.chromium.ui.modelutil.ListModel;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
/**
* This stateless class provides methods to bind a {@link ListModel<AccessorySheetDataPiece>}
* to the {@link RecyclerView} used as view of a tab for the accessory sheet component.
*/
class AccessorySheetTabViewBinder {
/** Holds any View that represents a list entry. */
abstract static class ElementViewHolder<T, V extends View> extends RecyclerView.ViewHolder {
ElementViewHolder(ViewGroup parent, int layout) {
super(LayoutInflater.from(parent.getContext()).inflate(layout, parent, false));
}
@SuppressWarnings("unchecked")
void bind(AccessorySheetDataPiece accessorySheetDataWrapper) {
bind((T) accessorySheetDataWrapper.getDataPiece(), (V) itemView);
}
protected abstract void bind(T t, V view);
}
/**
* Creates an {@link ElementViewHolder} for the given |viewType|.
* @param parent A {@link android.view.ViewParent} to attach this view to.
* @param viewType A {@link AccessorySheetDataPiece.Type} describing the view to be created.
* @return A {@link ElementViewHolder}.
*/
static ElementViewHolder create(ViewGroup parent, @AccessorySheetDataPiece.Type int viewType) {
switch (viewType) {
case AccessorySheetDataPiece.Type.TITLE:
return new TitleViewHolder(parent);
case AccessorySheetDataPiece.Type.FOOTER_COMMAND:
return new FooterCommandViewHolder(parent);
case AccessorySheetDataPiece.Type.OPTION_TOGGLE:
return new OptionToggleViewHolder(parent);
}
assert false : "Unhandled type of data piece: " + viewType;
return null;
}
/** Holds a Title consisting of a top divider, a text view and a bottom divider. */
static class TitleViewHolder extends ElementViewHolder<String, LinearLayout> {
TitleViewHolder(ViewGroup parent) {
this(parent, R.layout.keyboard_accessory_sheet_tab_legacy_title);
}
TitleViewHolder(ViewGroup parent, @LayoutRes int layout) {
super(parent, layout);
}
@Override
protected void bind(String displayText, LinearLayout view) {
TextView titleView = view.findViewById(R.id.tab_title);
titleView.setText(displayText);
titleView.setContentDescription(displayText);
}
}
/** Holds a clickable {@link TextView} that represents a footer command. */
static class FooterCommandViewHolder
extends ElementViewHolder<KeyboardAccessoryData.FooterCommand, TextView> {
FooterCommandViewHolder(ViewGroup parent) {
super(parent, R.layout.password_accessory_sheet_option);
}
@Override
protected void bind(KeyboardAccessoryData.FooterCommand footerCommand, TextView view) {
view.setText(footerCommand.getDisplayText());
view.setContentDescription(footerCommand.getDisplayText());
view.setOnClickListener(v -> footerCommand.execute());
}
}
/** Holds a title, subtitle which shows the state of the toggle and a toggle. */
static class OptionToggleViewHolder
extends ElementViewHolder<KeyboardAccessoryData.OptionToggle, LinearLayout> {
OptionToggleViewHolder(ViewGroup parent) {
super(parent, R.layout.keyboard_accessory_sheet_tab_option_toggle);
}
@Override
protected void bind(KeyboardAccessoryData.OptionToggle optionToggle, LinearLayout view) {
view.setClickable(true);
view.setOnClickListener(
v -> optionToggle.getCallback().onResult(!optionToggle.isEnabled()));
TextView titleText = view.findViewById(R.id.option_toggle_title);
titleText.setText(optionToggle.getDisplayText());
TextView subtitleText = view.findViewById(R.id.option_toggle_subtitle);
subtitleText.setText(optionToggle.isEnabled() ? R.string.text_on : R.string.text_off);
SwitchCompat switchView = view.findViewById(R.id.option_toggle_switch);
switchView.setChecked(optionToggle.isEnabled());
switchView.setBackground(null);
}
}
static void initializeView(
RecyclerView view, @Nullable RecyclerView.OnScrollListener scrollListener) {
view.setLayoutManager(
new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
view.setItemAnimator(null);
if (scrollListener != null) view.addOnScrollListener(scrollListener);
}
public static void bind(
PropertyModel model, AccessorySheetTabView view, PropertyKey propertyKey) {
if (propertyKey == ITEMS) {
// TODO(crbug.com/40257527): move setting adapter from initializeView() (in descendants)
} else if (propertyKey == SCROLL_LISTENER) {
// TODO(crbug.com/40257527): move setting listener from initializeView()
} else if (propertyKey == IS_DEFAULT_A11Y_FOCUS_REQUESTED) {
if (model.get(IS_DEFAULT_A11Y_FOCUS_REQUESTED)) {
view.requestDefaultA11yFocus();
}
} else {
assert false : "Binding property not implemented: " + propertyKey;
}
}
}