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 com.android.setupwizardlib.template;
18
19import android.annotation.SuppressLint;
20import android.content.Context;
21import android.support.annotation.NonNull;
22import android.support.annotation.Nullable;
23import android.support.annotation.StringRes;
24import android.support.annotation.StyleRes;
25import android.view.ContextThemeWrapper;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewStub;
29import android.widget.Button;
30import android.widget.LinearLayout;
31import android.widget.LinearLayout.LayoutParams;
32
33import com.android.setupwizardlib.R;
34import com.android.setupwizardlib.TemplateLayout;
35
36/**
37 * A {@link Mixin} for managing buttons. By default, the button bar follows the GLIF design and
38 * expects that buttons on the start (left for LTR) are "secondary" borderless buttons, while
39 * buttons on the end (right for LTR) are "primary" accent-colored buttons.
40 */
41public class ButtonFooterMixin implements Mixin {
42
43    private final Context mContext;
44
45    @Nullable
46    private final ViewStub mFooterStub;
47
48    private LinearLayout mButtonContainer;
49
50    /**
51     * Create a mixin for managing buttons on the footer.
52     *
53     * @param layout The {@link TemplateLayout} containing this mixin.
54     */
55    public ButtonFooterMixin(TemplateLayout layout) {
56        mContext = layout.getContext();
57        mFooterStub = (ViewStub) layout.findManagedViewById(R.id.suw_layout_footer);
58    }
59
60    /**
61     * Add a button with the given text and style. Common style for GLIF are
62     * {@code SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
63     *
64     * @param text The label for the button.
65     * @param theme Theme resource to be used for this button. Since this is applied as a theme,
66     *              the resource will typically apply {@code android:buttonStyle} so it will be
67     *              applied to the button as a style as well.
68     *
69     * @return The button that was created.
70     */
71    public Button addButton(CharSequence text, @StyleRes int theme) {
72        Button button = createThemedButton(mContext, theme);
73        button.setText(text);
74        return addButton(button);
75    }
76
77    /**
78     * Add a button with the given text and style. Common style for GLIF are
79     * {@code SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
80     *
81     * @param text The label for the button.
82     * @param theme Theme resource to be used for this button. Since this is applied as a theme,
83     *              the resource will typically apply {@code android:buttonStyle} so it will be
84     *              applied to the button as a style as well.
85     *
86     * @return The button that was created.
87     */
88    public Button addButton(@StringRes int text, @StyleRes int theme) {
89        Button button = createThemedButton(mContext, theme);
90        button.setText(text);
91        return addButton(button);
92    }
93
94    /**
95     * Add a button to the footer.
96     *
97     * @param button The button to be added to the footer.
98     * @return The button that was added.
99     */
100    public Button addButton(Button button) {
101        final LinearLayout buttonContainer = ensureFooterInflated();
102        buttonContainer.addView(button);
103        return button;
104    }
105
106    /**
107     * Add a space to the footer. Spaces will share the remaining space of footer, so for example,
108     * [Button] [space] [Button] [space] [Button] will give you 3 buttons, left, center, and right
109     * aligned.
110     *
111     * @return The view that was used as space.
112     */
113    public View addSpace() {
114        final LinearLayout buttonContainer = ensureFooterInflated();
115        View space = new View(buttonContainer.getContext());
116        space.setLayoutParams(new LayoutParams(0, 0, 1.0f));
117        space.setVisibility(View.INVISIBLE);
118        buttonContainer.addView(space);
119        return space;
120    }
121
122    /**
123     * Remove a previously added button.
124     *
125     * @param button The button to be removed.
126     */
127    public void removeButton(Button button) {
128        if (mButtonContainer != null) {
129            mButtonContainer.removeView(button);
130        }
131    }
132
133    /**
134     * Remove a previously added space.
135     *
136     * @param space The space to be removed.
137     */
138    public void removeSpace(View space) {
139        if (mButtonContainer != null) {
140            mButtonContainer.removeView(space);
141        }
142    }
143
144    /**
145     * Remove all views, including spaces, from the footer. Note that if the footer container is
146     * already inflated, this will not remove the container itself.
147     */
148    public void removeAllViews() {
149        if (mButtonContainer != null) {
150            mButtonContainer.removeAllViews();
151        }
152    }
153
154    @NonNull
155    private LinearLayout ensureFooterInflated() {
156        if (mButtonContainer == null) {
157            if (mFooterStub == null) {
158                throw new IllegalStateException("Footer stub is not found in this template");
159            }
160            mFooterStub.setLayoutResource(R.layout.suw_glif_footer_button_bar);
161            mButtonContainer = (LinearLayout) mFooterStub.inflate();
162        }
163        return mButtonContainer;
164    }
165
166    @SuppressLint("InflateParams")
167    private Button createThemedButton(Context context, @StyleRes int theme) {
168        // Inflate a single button from XML, which when using support lib, will take advantage of
169        // the injected layout inflater and give us AppCompatButton instead.
170        LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(context, theme));
171        return (Button) inflater.inflate(R.layout.suw_button, null, false);
172    }
173}
174