1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.wear.internal.widget.drawer;
18
19import android.graphics.drawable.Drawable;
20import android.os.Handler;
21import android.os.Looper;
22import android.support.annotation.IdRes;
23import android.support.annotation.LayoutRes;
24import android.support.annotation.Nullable;
25import android.support.annotation.RestrictTo;
26import android.support.annotation.RestrictTo.Scope;
27import android.support.wear.R;
28import android.support.wear.widget.CircledImageView;
29import android.support.wear.widget.drawer.WearableNavigationDrawerView;
30import android.view.Gravity;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.widget.TextView;
34import android.widget.Toast;
35
36/**
37 * Handles view logic for the single page style {@link WearableNavigationDrawerView}.
38 *
39 * @hide
40 */
41@RestrictTo(Scope.LIBRARY_GROUP)
42public class SinglePageUi implements SinglePagePresenter.Ui {
43
44    @IdRes
45    private static final int[] SINGLE_PAGE_BUTTON_IDS =
46            new int[]{
47                    R.id.wearable_support_nav_drawer_icon_0,
48                    R.id.wearable_support_nav_drawer_icon_1,
49                    R.id.wearable_support_nav_drawer_icon_2,
50                    R.id.wearable_support_nav_drawer_icon_3,
51                    R.id.wearable_support_nav_drawer_icon_4,
52                    R.id.wearable_support_nav_drawer_icon_5,
53                    R.id.wearable_support_nav_drawer_icon_6,
54            };
55
56    @LayoutRes
57    private static final int[] SINGLE_PAGE_LAYOUT_RES =
58            new int[]{
59                    0,
60                    R.layout.single_page_nav_drawer_1_item,
61                    R.layout.single_page_nav_drawer_2_item,
62                    R.layout.single_page_nav_drawer_3_item,
63                    R.layout.single_page_nav_drawer_4_item,
64                    R.layout.single_page_nav_drawer_5_item,
65                    R.layout.single_page_nav_drawer_6_item,
66                    R.layout.single_page_nav_drawer_7_item,
67            };
68
69    private final WearableNavigationDrawerView mDrawer;
70    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
71    private final Runnable mCloseDrawerRunnable =
72            new Runnable() {
73                @Override
74                public void run() {
75                    mDrawer.getController().closeDrawer();
76                }
77            };
78    private WearableNavigationDrawerPresenter mPresenter;
79    private CircledImageView[] mSinglePageImageViews;
80    /**
81     * Indicates currently selected item. {@code null} when the layout lacks space to display it.
82     */
83    @Nullable
84    private TextView mTextView;
85
86    public SinglePageUi(WearableNavigationDrawerView navigationDrawer) {
87        if (navigationDrawer == null) {
88            throw new IllegalArgumentException("Received null navigationDrawer.");
89        }
90        mDrawer = navigationDrawer;
91    }
92
93    @Override
94    public void setPresenter(WearableNavigationDrawerPresenter presenter) {
95        mPresenter = presenter;
96    }
97
98    @Override
99    public void initialize(int count) {
100        if (count < 0 || count >= SINGLE_PAGE_LAYOUT_RES.length
101                || SINGLE_PAGE_LAYOUT_RES[count] == 0) {
102            mDrawer.setDrawerContent(null);
103            return;
104        }
105
106        @LayoutRes int layoutRes = SINGLE_PAGE_LAYOUT_RES[count];
107        LayoutInflater inflater = LayoutInflater.from(mDrawer.getContext());
108        View content = inflater.inflate(layoutRes, mDrawer, false /* attachToRoot */);
109        final View peek =
110                inflater.inflate(
111                        R.layout.single_page_nav_drawer_peek_view, mDrawer,
112                        false /* attachToRoot */);
113
114        mTextView = (TextView) content.findViewById(R.id.wearable_support_nav_drawer_text);
115        mSinglePageImageViews = new CircledImageView[count];
116        for (int i = 0; i < count; i++) {
117            mSinglePageImageViews[i] = (CircledImageView) content
118                    .findViewById(SINGLE_PAGE_BUTTON_IDS[i]);
119            mSinglePageImageViews[i].setOnClickListener(new OnSelectedClickHandler(i, mPresenter));
120            mSinglePageImageViews[i].setCircleHidden(true);
121        }
122
123        mDrawer.setDrawerContent(content);
124        mDrawer.setPeekContent(peek);
125    }
126
127    @Override
128    public void setIcon(int index, Drawable drawable, CharSequence contentDescription) {
129        mSinglePageImageViews[index].setImageDrawable(drawable);
130        mSinglePageImageViews[index].setContentDescription(contentDescription);
131    }
132
133    @Override
134    public void setText(CharSequence itemText, boolean showToastIfNoTextView) {
135        if (mTextView != null) {
136            mTextView.setText(itemText);
137        } else if (showToastIfNoTextView) {
138            Toast toast = Toast.makeText(mDrawer.getContext(), itemText, Toast.LENGTH_SHORT);
139            toast.setGravity(Gravity.CENTER, 0 /* xOffset */, 0 /* yOffset */);
140            toast.show();
141        }
142    }
143
144    @Override
145    public void selectItem(int index) {
146        mSinglePageImageViews[index].setCircleHidden(false);
147    }
148
149    @Override
150    public void deselectItem(int index) {
151        mSinglePageImageViews[index].setCircleHidden(true);
152    }
153
154    @Override
155    public void closeDrawerDelayed(long delayMs) {
156        mMainThreadHandler.removeCallbacks(mCloseDrawerRunnable);
157        mMainThreadHandler.postDelayed(mCloseDrawerRunnable, delayMs);
158    }
159
160    @Override
161    public void peekDrawer() {
162        mDrawer.getController().peekDrawer();
163    }
164
165    /**
166     * Notifies the {@code presenter} that the item at the given {@code index} has been selected.
167     */
168    private static class OnSelectedClickHandler implements View.OnClickListener {
169
170        private final int mIndex;
171        private final WearableNavigationDrawerPresenter mPresenter;
172
173        private OnSelectedClickHandler(int index, WearableNavigationDrawerPresenter presenter) {
174            mIndex = index;
175            mPresenter = presenter;
176        }
177
178        @Override
179        public void onClick(View v) {
180            mPresenter.onSelected(mIndex);
181        }
182    }
183}
184