Skip to content

Commit 3f665f2

Browse files
committed
Add drop down with special chars for Characters
Custom DialogPreference with special character presets for character preference settings in custom format. Closes #37 Signed-off-by: Aron Heinecke <[email protected]>
1 parent de59c88 commit 3f665f2

File tree

12 files changed

+279
-75
lines changed

12 files changed

+279
-75
lines changed

app/src/main/java/vocabletrainer/heinecke/aron/vocabletrainer/fragment/ExportFragment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private void initView(@Nullable Bundle savedInstanceState) {
221221
Button btnFileDialog = view.findViewById(R.id.bExportSelFile);
222222
btnFileDialog.setOnClickListener(v -> selectFile());
223223

224-
spAdapterFormat = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item);
224+
spAdapterFormat = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item);
225225
spAdapterFormat.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
226226

227227
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);

app/src/main/java/vocabletrainer/heinecke/aron/vocabletrainer/fragment/FormatFragment.java

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,13 @@
99
import android.support.v7.app.ActionBar;
1010
import android.support.v7.app.AlertDialog;
1111
import android.support.v7.preference.EditTextPreference;
12-
import android.support.v7.preference.EditTextPreferenceDialogFragmentCompat;
1312
import android.support.v7.preference.Preference;
1413
import android.support.v7.preference.PreferenceFragmentCompat;
1514
import android.text.InputFilter;
1615
import android.util.Log;
1716
import android.view.Menu;
1817
import android.view.MenuInflater;
1918
import android.view.MenuItem;
20-
import android.view.View;
21-
import android.widget.EditText;
2219

2320
import org.apache.commons.csv.CSVFormat;
2421
import org.apache.commons.csv.Constants;
@@ -28,8 +25,9 @@
2825
import vocabletrainer.heinecke.aron.vocabletrainer.R;
2926
import vocabletrainer.heinecke.aron.vocabletrainer.activity.FragmentActivity;
3027
import vocabletrainer.heinecke.aron.vocabletrainer.lib.CSV.CSVCustomFormat;
31-
import vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget.CustomEditTextPreference;
3228
import vocabletrainer.heinecke.aron.vocabletrainer.lib.ViewModel.FormatViewModel;
29+
import vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget.CharacterPreference;
30+
import vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget.CharacterPreferenceDialog;
3331

3432
/**
3533
* Fragment for custom cFormat preferences<br>
@@ -288,13 +286,15 @@ public void onDisplayPreferenceDialog(Preference preference) {
288286
// hack for custom dialog to allow for edittext filters
289287

290288
// dialog shown
289+
//noinspection ConstantConditions
291290
if (getFragmentManager().findFragmentByTag(C_DIALOG_TAG) != null) {
292291
return;
293292
}
294293

295294
DialogFragment f = null;
296-
if (preference instanceof CustomEditTextPreference) {
297-
f = EditTextPreferenceDialog.newInstance(preference.getKey(),lengthFilter);
295+
if (preference instanceof CharacterPreference) {
296+
//f = EditTextPreferenceDialog.newInstance(preference.getKey(),lengthFilter);
297+
f = CharacterPreferenceDialog.newInstance(preference);
298298
} else {
299299
super.onDisplayPreferenceDialog(preference);
300300
}
@@ -326,28 +326,4 @@ public boolean onBackPressed() {
326326
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
327327
verifyFormat();
328328
}
329-
330-
/**
331-
* Custom EditText preference dialog to allow for Filters
332-
* Because correct Android is hard.
333-
*/
334-
public static class EditTextPreferenceDialog extends EditTextPreferenceDialogFragmentCompat {
335-
private InputFilter[] filters;
336-
337-
public static EditTextPreferenceDialog newInstance(String key, InputFilter[] filters) {
338-
final EditTextPreferenceDialog
339-
fragment = new EditTextPreferenceDialog();
340-
final Bundle b = new Bundle(1);
341-
b.putString(ARG_KEY, key);
342-
fragment.setArguments(b);
343-
fragment.filters = filters;
344-
return fragment;
345-
}
346-
347-
@Override
348-
protected void onBindDialogView(View view) {
349-
super.onBindDialogView(view);
350-
((EditText)view.findViewById(android.R.id.edit)).setFilters(filters);
351-
}
352-
}
353329
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget;
2+
3+
import android.content.Context;
4+
import android.support.v7.preference.EditTextPreference;
5+
import android.util.AttributeSet;
6+
7+
import vocabletrainer.heinecke.aron.vocabletrainer.R;
8+
9+
/**
10+
* Custom EditTextPreference for single character settings
11+
* Created by Aron Heinecke
12+
*/
13+
public class CharacterPreference extends EditTextPreference {
14+
public CharacterPreference(Context context, AttributeSet attrs, int defStyleAttr,
15+
int defStyleRes) {
16+
super(context, attrs, defStyleAttr, defStyleRes);
17+
}
18+
public CharacterPreference(Context context, AttributeSet attrs, int defStyleAttr) {
19+
super(context, attrs, defStyleAttr);
20+
}
21+
22+
public CharacterPreference(Context context) {
23+
super(context);
24+
}
25+
26+
public CharacterPreference(Context context, AttributeSet attrs) {
27+
this(context, attrs, R.attr.dialogPreferenceStyle);
28+
}
29+
30+
@Override
31+
public int getDialogLayoutResource() {
32+
return R.layout.dialog_character_preference;
33+
}
34+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget;
2+
3+
import android.app.AlertDialog;
4+
import android.app.Dialog;
5+
import android.os.Bundle;
6+
import android.support.annotation.NonNull;
7+
import android.support.design.widget.TextInputEditText;
8+
import android.support.design.widget.TextInputLayout;
9+
import android.support.v7.preference.DialogPreference;
10+
import android.support.v7.preference.EditTextPreference;
11+
import android.support.v7.preference.Preference;
12+
import android.support.v7.preference.PreferenceDialogFragmentCompat;
13+
import android.text.Editable;
14+
import android.text.TextWatcher;
15+
import android.view.View;
16+
import android.widget.AdapterView;
17+
import android.widget.ArrayAdapter;
18+
import android.widget.Button;
19+
import android.widget.Spinner;
20+
21+
import vocabletrainer.heinecke.aron.vocabletrainer.R;
22+
import vocabletrainer.heinecke.aron.vocabletrainer.lib.Storage.GenericSpinnerEntry;
23+
24+
/**
25+
* Character Preference Dialog
26+
*/
27+
public class CharacterPreferenceDialog extends PreferenceDialogFragmentCompat {
28+
private static final int MAX_LENGTH = 1;
29+
private static final String ARG_TITLE = "title";
30+
private static String PLACEHOLDER;
31+
TextInputEditText charInput;
32+
TextInputLayout charInputLayout;
33+
Spinner spPreset;
34+
ArrayAdapter<GenericSpinnerEntry<Character>> adapter;
35+
private CustomItemSelectedListener listener;
36+
private Button okButton;
37+
38+
public static CharacterPreferenceDialog newInstance(Preference preference) {
39+
final CharacterPreferenceDialog
40+
fragment = new CharacterPreferenceDialog();
41+
final Bundle b = new Bundle(1);
42+
b.putString(ARG_KEY, preference.getKey());
43+
b.putString(ARG_TITLE, preference.getTitle().toString());
44+
fragment.setArguments(b);
45+
return fragment;
46+
}
47+
48+
@NonNull
49+
@Override
50+
public Dialog onCreateDialog(Bundle savedInstanceState) {
51+
Dialog dialog = super.onCreateDialog(savedInstanceState);
52+
okButton = dialog.findViewById(AlertDialog.BUTTON_POSITIVE);
53+
return dialog;
54+
}
55+
56+
@Override
57+
protected void onBindDialogView(View view) {
58+
super.onBindDialogView(view);
59+
PLACEHOLDER = getString(R.string.Placeholder);
60+
DialogPreference preference = getPreference();
61+
62+
charInput = view.findViewById(R.id.tCharInput);
63+
charInputLayout = view.findViewById(R.id.tCharInputLayout);
64+
charInputLayout.setCounterEnabled(true);
65+
charInputLayout.setCounterMaxLength(MAX_LENGTH);
66+
String hint = getArguments().getString(ARG_TITLE,PLACEHOLDER);
67+
charInputLayout.setHint(hint);
68+
charInput.setSingleLine();
69+
charInput.setHint(hint);
70+
charInput.setText(((EditTextPreference) preference).getText());
71+
spPreset = view.findViewById(R.id.spPreset);
72+
73+
adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item);
74+
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
75+
adapter.add(new GenericSpinnerEntry<>(null,getString(R.string.Character_Custom)));
76+
adapter.add(new GenericSpinnerEntry<>('\t',getString(R.string.Character_Tab)));
77+
adapter.add(new GenericSpinnerEntry<>('\r',getString(R.string.Character_Line_Feed)));
78+
adapter.add(new GenericSpinnerEntry<>(',',getString(R.string.Character_Comma)));
79+
adapter.add(new GenericSpinnerEntry<>(';',getString(R.string.Character_Semicolon)));
80+
adapter.add(new GenericSpinnerEntry<>('"',getString(R.string.Character_Quotations_Mark)));
81+
adapter.add(new GenericSpinnerEntry<>('\\',getString(R.string.Character_Backslash)));
82+
spPreset.setAdapter(adapter);
83+
84+
listener = new CustomItemSelectedListener() {
85+
@Override
86+
public void itemSelected(AdapterView<?> parent, View view, int position, long id) {
87+
Character selected = adapter.getItem(position).getObject();
88+
if(selected != null){
89+
charInput.setText(String.valueOf(selected));
90+
}
91+
}
92+
};
93+
94+
spPreset.setOnItemSelectedListener(listener);
95+
96+
charInput.addTextChangedListener(new TextWatcher() {
97+
@Override
98+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
99+
100+
}
101+
102+
@Override
103+
public void onTextChanged(CharSequence s, int start, int before, int count) {
104+
105+
}
106+
107+
@Override
108+
public void afterTextChanged(Editable s) {
109+
//listener.disableNextEvent();
110+
updateSpinner();
111+
int length = s.toString().toCharArray().length;
112+
if(length == MAX_LENGTH){
113+
charInputLayout.setError(null);
114+
}else{
115+
charInputLayout.setError(getString(R.string.Character_Incorrect_Amount));
116+
}
117+
}
118+
});
119+
}
120+
121+
private void updateSpinner(){
122+
String input = charInput.getText().toString();
123+
switch(input){
124+
case "\t":
125+
spPreset.setSelection(1);
126+
break;
127+
case "\r":
128+
spPreset.setSelection(2);
129+
break;
130+
case ",":
131+
spPreset.setSelection(3);
132+
break;
133+
case ";":
134+
spPreset.setSelection(4);
135+
break;
136+
case "\"":
137+
spPreset.setSelection(5);
138+
break;
139+
case "\\":
140+
spPreset.setSelection(6);
141+
break;
142+
default:
143+
spPreset.setSelection(0);
144+
if(input.length() == MAX_LENGTH) {
145+
adapter.getItem(0).updateObject(input.charAt(0));
146+
}
147+
}
148+
}
149+
150+
@Override
151+
public void onDialogClosed(boolean positiveResult) {
152+
if(positiveResult && charInputLayout.getError() == null){
153+
DialogPreference preference = getPreference();
154+
if (preference instanceof EditTextPreference) {
155+
EditTextPreference textPreference =
156+
((EditTextPreference) preference);
157+
// This allows the client to ignore the user value.
158+
if(textPreference.callChangeListener(charInput.getText().toString())){
159+
textPreference.setText(charInput.getText().toString());
160+
}
161+
}
162+
}
163+
}
164+
}

app/src/main/java/vocabletrainer/heinecke/aron/vocabletrainer/lib/Widget/CustomEditTextPreference.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

app/src/main/java/vocabletrainer/heinecke/aron/vocabletrainer/lib/Widget/CustomItemSelectedListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public final void onItemSelected(AdapterView<?> parent, View view, int position,
2020
/**
2121
* Set firstSelect as undone, disabling the next itemSelect call from triggering itemSelected
2222
*/
23-
public void setFirstUnselected() {
23+
public void disableNextEvent() {
2424
this.firstSelect = true;
2525
}
2626

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:gravity="center"
7+
android:orientation="vertical"
8+
android:padding="16dp"
9+
tools:context="vocabletrainer.heinecke.aron.vocabletrainer.lib.Widget.CharacterPreference">
10+
11+
<android.support.design.widget.TextInputLayout
12+
android:id="@+id/tCharInputLayout"
13+
android:layout_width="match_parent"
14+
android:layout_height="wrap_content">
15+
16+
<android.support.design.widget.TextInputEditText
17+
android:id="@+id/tCharInput"
18+
android:hint="@string/Placeholder"
19+
android:layout_width="match_parent"
20+
android:maxLength="1"
21+
android:layout_height="wrap_content" />
22+
</android.support.design.widget.TextInputLayout>
23+
24+
<TextView
25+
style="@style/InputLabel"
26+
android:paddingTop="8dp"
27+
android:layout_width="match_parent"
28+
android:layout_height="wrap_content"
29+
android:text="@string/Character_Preference_Preset_Label" />
30+
31+
<Spinner
32+
android:id="@+id/spPreset"
33+
android:layout_width="match_parent"
34+
android:layout_height="wrap_content" />
35+
36+
</LinearLayout>

app/src/main/res/values/dimens.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
<dimen name="ic_delete">30dp</dimen>
55
<dimen name="padd_10">10dp</dimen>
66
<dimen name="high_density">48dp</dimen>
7+
<dimen name="input_label_vertical_spacing">8dp</dimen>
8+
<dimen name="input_label_horizontal_spacing">4dp</dimen>
79
</resources>

app/src/main/res/values/strings.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
<string name="File_Diag_btn_OK">Overwrite</string>
126126
<string name="File_Diag_btn_CANCEL">Cancel</string>
127127
<!-- Messages -->
128+
<string name="Character_Incorrect_Amount">Incorrect character amount!</string>
128129
<string name="Perm_CSV">Permission is required to load/write your CSV files for import/export.</string>
129130
<string name="File_Error_Mediastate">No storage found / is writable! Unable to continue.</string>
130131
<string name="File_Error_Nullpointer">Unable to show files. Nullpointer</string>
@@ -136,6 +137,14 @@
136137
<string name="Import_Warn_MAX_RECORD_SIZE">Entry has too many values: </string>
137138
<string name="Import_Info_Import">Imported %d vocables</string>
138139
<!-- Spinner -->
140+
<string name="Character_Tab">Tab (\\t)</string>
141+
<string name="Character_Comma">Comma (,)</string>
142+
<string name="Character_Backslash">Backslash (\\)</string>
143+
<string name="Character_Line_Feed">Line Feed (\\r)</string>
144+
<string name="Character_Semicolon">Semicolon (;)</string>
145+
<string name="Character_Quotations_Mark">Quotation Mark (\")</string>
146+
<string name="Character_Custom">Custom Character</string>
147+
139148
<string name="Import_Multilist_REPLACE">Replace existing lists</string>
140149
<string name="Import_Multilist_IGNORE">Ignore existing lists</string>
141150
<string name="Import_Multilist_ADD">Append if list exists</string>
@@ -158,6 +167,7 @@
158167
<string name="title_activity_format">FormatActivity</string>
159168

160169
<!--format preferences -->
170+
<string name="Character_Preference_Preset_Label">Presets</string>
161171
<string name="Pref_Multi_Transl">Multi-Translations</string>
162172
<string name="Pref_Multi_Transl_Desc">Handle multiple translations</string>
163173
<string name="Pref_Multi_Transl_Char">Multi-Translation Delimiter Char</string>

0 commit comments

Comments
 (0)