1 /*
2  * Copyright (C) 2012 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 
17 package com.android.deskclock;
18 
19 import android.app.Dialog;
20 import android.app.DialogFragment;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.res.ColorStateList;
24 import android.os.Bundle;
25 import android.support.annotation.NonNull;
26 import android.support.v7.app.AlertDialog;
27 import android.support.v7.widget.AppCompatEditText;
28 import android.text.Editable;
29 import android.text.InputType;
30 import android.text.TextUtils;
31 import android.text.TextWatcher;
32 import android.view.KeyEvent;
33 import android.view.inputmethod.EditorInfo;
34 import android.widget.TextView;
35 
36 import com.android.deskclock.data.DataModel;
37 import com.android.deskclock.data.Timer;
38 import com.android.deskclock.provider.Alarm;
39 
40 import static android.graphics.Color.RED;
41 import static android.graphics.Color.WHITE;
42 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
43 
44 /**
45  * DialogFragment to edit label.
46  */
47 public class LabelDialogFragment extends DialogFragment {
48 
49     private static final String KEY_LABEL = "label";
50     private static final String KEY_ALARM = "alarm";
51     private static final String KEY_TIMER_ID = "timer_id";
52     private static final String KEY_TAG = "tag";
53 
54     private AppCompatEditText mLabelBox;
55     private Alarm mAlarm;
56     private int mTimerId;
57     private String mTag;
58 
newInstance(Alarm alarm, String label, String tag)59     public static LabelDialogFragment newInstance(Alarm alarm, String label, String tag) {
60         final Bundle args = new Bundle();
61         args.putString(KEY_LABEL, label);
62         args.putParcelable(KEY_ALARM, alarm);
63         args.putString(KEY_TAG, tag);
64 
65         final LabelDialogFragment frag = new LabelDialogFragment();
66         frag.setArguments(args);
67         return frag;
68     }
69 
newInstance(Timer timer)70     public static LabelDialogFragment newInstance(Timer timer) {
71         final Bundle args = new Bundle();
72         args.putString(KEY_LABEL, timer.getLabel());
73         args.putInt(KEY_TIMER_ID, timer.getId());
74 
75         final LabelDialogFragment frag = new LabelDialogFragment();
76         frag.setArguments(args);
77         return frag;
78     }
79 
80     @Override
onSaveInstanceState(@onNull Bundle outState)81     public void onSaveInstanceState(@NonNull Bundle outState) {
82         super.onSaveInstanceState(outState);
83         outState.putString(KEY_LABEL, mLabelBox.getText().toString());
84     }
85 
86     @Override
onCreateDialog(Bundle savedInstanceState)87     public Dialog onCreateDialog(Bundle savedInstanceState) {
88         final Bundle bundle = getArguments();
89         mAlarm = bundle.getParcelable(KEY_ALARM);
90         mTimerId = bundle.getInt(KEY_TIMER_ID, -1);
91         mTag = bundle.getString(KEY_TAG);
92 
93         final String label = savedInstanceState != null ?
94                 savedInstanceState.getString(KEY_LABEL) : bundle.getString(KEY_LABEL);
95 
96         final Context context = getActivity();
97 
98         mLabelBox = new AppCompatEditText(context);
99         mLabelBox.setOnEditorActionListener(new ImeDoneListener());
100         mLabelBox.addTextChangedListener(new TextChangeListener(context));
101         mLabelBox.setSingleLine();
102         mLabelBox.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
103         mLabelBox.setText(label);
104         mLabelBox.selectAll();
105 
106         final int padding = getResources().getDimensionPixelSize(R.dimen.label_edittext_padding);
107         final AlertDialog alertDialog = new AlertDialog.Builder(context)
108                 .setView(mLabelBox, padding, 0, padding, 0)
109                 .setPositiveButton(R.string.time_picker_set, new OkListener())
110                 .setNegativeButton(R.string.time_picker_cancel, new CancelListener())
111                 .setMessage(R.string.label)
112                 .create();
113 
114         alertDialog.getWindow().setSoftInputMode(SOFT_INPUT_STATE_VISIBLE);
115         return alertDialog;
116     }
117 
118     /**
119      * Sets the new label into the timer or alarm.
120      */
setLabel()121     private void setLabel() {
122         String label = mLabelBox.getText().toString();
123         if (label.trim().isEmpty()) {
124             // Don't allow user to input label with only whitespace.
125             label = "";
126         }
127 
128         if (mAlarm != null) {
129             ((AlarmLabelDialogHandler) getActivity()).onDialogLabelSet(mAlarm, label, mTag);
130         } else if (mTimerId >= 0) {
131             final Timer timer = DataModel.getDataModel().getTimer(mTimerId);
132             if (timer != null) {
133                 DataModel.getDataModel().setTimerLabel(timer, label);
134             }
135         }
136     }
137 
138     interface AlarmLabelDialogHandler {
onDialogLabelSet(Alarm alarm, String label, String tag)139         void onDialogLabelSet(Alarm alarm, String label, String tag);
140     }
141 
142     /**
143      * Alters the UI to indicate when input is valid or invalid.
144      */
145     private class TextChangeListener implements TextWatcher {
146 
147         private final int colorAccent;
148         private final int colorControlNormal;
149 
TextChangeListener(Context context)150         public TextChangeListener(Context context) {
151             colorAccent = Utils.obtainStyledColor(context, R.attr.colorAccent, RED);
152             colorControlNormal = Utils.obtainStyledColor(context, R.attr.colorControlNormal, WHITE);
153         }
154 
155         @Override
onTextChanged(CharSequence s, int start, int before, int count)156         public void onTextChanged(CharSequence s, int start, int before, int count) {
157             final int color = TextUtils.isEmpty(s) ? colorControlNormal : colorAccent;
158             mLabelBox.setSupportBackgroundTintList(ColorStateList.valueOf(color));
159         }
160 
161         @Override
beforeTextChanged(CharSequence s, int start, int count, int after)162         public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
163 
164         @Override
afterTextChanged(Editable editable)165         public void afterTextChanged(Editable editable) {}
166     }
167 
168     /**
169      * Handles completing the label edit from the IME keyboard.
170      */
171     private class ImeDoneListener implements TextView.OnEditorActionListener {
172         @Override
onEditorAction(TextView v, int actionId, KeyEvent event)173         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
174             if (actionId == EditorInfo.IME_ACTION_DONE) {
175                 setLabel();
176                 dismiss();
177                 return true;
178             }
179             return false;
180         }
181     }
182 
183     /**
184      * Handles completing the label edit from the Ok button of the dialog.
185      */
186     private class OkListener implements DialogInterface.OnClickListener {
187         @Override
onClick(DialogInterface dialog, int which)188         public void onClick(DialogInterface dialog, int which) {
189             setLabel();
190             dismiss();
191         }
192     }
193 
194     /**
195      * Handles discarding the label edit from the Cancel button of the dialog.
196      */
197     private class CancelListener implements DialogInterface.OnClickListener {
198         @Override
onClick(DialogInterface dialog, int which)199         public void onClick(DialogInterface dialog, int which) {
200             dismiss();
201         }
202     }
203 }