chromium/docs/ui/android/mvc_simple_list_tutorial.md

# Simple Lists in MVC Land

### Overview
This tutorial is intended to go over a basic implementation of lists in the Chrome on Android MVC
framework. If you're not sure what MVC is, see [Additional Resources](#Additional-Resources).

In this example we'll be creating a simple menu list where each list item consists of an icon and
label.

### Additional Resources
* [Introductory MVC tutorial][mvc_tutorial_link]
* [Expanding to RecyclerViews in MVC][mvc_recycler_view_tutorial]

### File Structure
The file structure of our component will be the following:
* ./chrome/android/java/src/org/chromium/chrome/browser/simple_menu/
  * [`SimpleMenuCoordinator.java`](#SimpleMenuCoordinator)
  * [`SimpleMenuMediator.java`](#SimpleMenuMediator)
  * [`SimpleMenuItemViewBinder.java`](#SimpleMenuItemViewBinder)
  * [`SimpleMenuProperties.java`](#SimpleMenuProperties)
* ./chrome/android/java/res/layout/
  * [`simple_menu_item.xml`](#simple_menu_item_xml)

### SimpleMenuCoordinator
This class will own the ```ModelListAdapter``` that knows how to show ```PropertyModels```. In
this example we'll be combining the responsibilities of what would otherwise be the coordinator
and mediator for simplicity.

```java
public class SimpleMenuCoordinator {

    private SimpleMenuMediator mMediator;

    public SimpleMenuCoordinator(Context context, ListView listView) {
        ModelList listItems = new ModelList();

        // Once this is attached to the ListView, there is no need to hold a reference to it.
        ModelListAdapter adapter = new ModelListAdapter(listItems);

        // If this is a heterogeneous list, register more than one type.
        adapter.registerType(
                ListItemType.DEFAULT,
                () -> LayoutInflater.from(context).inflate(R.layout.simple_menu_item, null),
                SimpleMenuItemViewBinder::bind);

        listView.setAdapter(adapter);

        mMediator = new SimpleMenuMediator(context, listItems);
    }
}
```

### SimpleMenuMediator
This class is responsible for pushing updates into the ```ModelList```. Updates to that
object are automatically pushed and bound to the list view. For a more complex system, the
```ModelList``` may be part of a larger ```PropertyModel``` that the mediator maintains.
```java
class SimpleMenuMediator {

    private ModelList mModelList;

    SimpleMenuMediator(Context context, ModelList modelList) {
        mModelList = modelList;
        PropertyModel itemModel = generateListItem(
                ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.icon),
                context.getResources().getString(R.string.label));
        mModelList.add(new ModelListAdapter.ListItem(ListItemType.DEFAULT, itemModel));
    }

    private PropertyModel generateListItem(Drawable icon, String text) {
        return new PropertyModel.Builder(SimpleMenuProperties.ALL_KEYS)
                .with(SimpleMenuProperties.ICON, icon)
                .with(SimpleMenuProperties.LABEL, text)
                .with(SimpleMenuProperties.CLICK_LISTENER, (view) -> handleClick(view))
                .build();
    }

    private void handleClick(View view) {
        // Do some click logic here. This would typically be done in the mediator.
    }
}
```


### SimpleMenuProperties
These are the types of data that we want to apply to each list item in our menu.
```java
class SimpleMenuProperties {
    @IntDef({ListItemType.DEFAULT})
    @Retention(RetentionPolicy.SOURCE)
    /**
     * This can be one or more items depending on if the list is homogeneous. If homogeneous,
     * this definition can be skipped and 0 can be used in place of that parameter.
     */
    public @interface ListItemType {
        int DEFAULT = 0;
    }

    /** The icon for the list item. */
    public static final WritableObjectPropertyKey<Drawable> ICON =
            new WritableObjectPropertyKey<>();

    /** The text shown next to the icon. */
    public static final WritableObjectPropertyKey<String> LABEL =
            new WritableObjectPropertyKey<>();

    /** The action that occurs when the list item is tapped. */
    public static final WritableObjectPropertyKey<OnClickListener> CLICK_LISTENER =
            new WritableObjectPropertyKey<>();

    public static final PropertyKey[] ALL_KEYS = {ICON, LABEL, CLICK_LISTENER};
}
```

### SimpleMenuItemViewBinder
As per the MVC architecture, this class is responsible for taking a model and applying that
information in to to a provided view.
```java
class SimpleMenuItemViewBinder {

    // This can optionally be in the coordinator file depending on the complexity.
    public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
        if (SimpleMenuProperties.ICON == propertyKey) {
            ((ImageView) view.findViewById(R.id.simple_menu_icon)).setImageDrawable(
                    model.get(SimpleMenuProperties.ICON));

        } else if (SimpleMenuProperties.LABEL == propertyKey) {
            ((TextView) view.findViewById(R.id.simple_menu_label)).setText(
                    model.get(SimpleMenuProperties.LABEL));

        } else if (SimpleMenuProperties.CLICK_LISTENER == propertyKey) {
            view.setOnClickListener(model.get(SimpleMenuProperties.CLICK_LISTENER));
        }
    }
}
```

### simple_menu_item.xml
```xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors
     Use of this source code is governed by a BSD-style license that can be
     found in the LICENSE file. -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@color/modern_primary_color">

    <org.chromium.ui.widget.ChromeImageView
        android:id="@+id/simple_menu_icon"
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_gravity="center_vertical"
        android:scaleType="centerInside"/>

    <TextView
        android:id="@+id/simple_menu_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:textAppearance="@style/TextAppearance.BlackBody"/>

</LinearLayout>
```

[mvc_tutorial_link]:https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_architecture_tutorial.md
[mvc_recycler_view_tutorial]:https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_simple_recycler_view_tutorial.md