diff options
| author | Menny Even Danan <menny@evendanan.net> | 2015-05-27 13:15:47 +0000 |
|---|---|---|
| committer | Menny Even Danan <menny@evendanan.net> | 2015-05-27 13:15:47 +0000 |
| commit | 48a3d1f2ba1a574db68e801323846e10d3219bf6 (patch) | |
| tree | 77fbc18f1f82bbd5f3ecbfa037995ad0783a2b24 | |
| parent | 717809cf50e7b2729872a6251a9a50af6c4d99dd (diff) | |
| download | AnySoftKeyboard-48a3d1f2ba1a574db68e801323846e10d3219bf6.tar.gz AnySoftKeyboard-48a3d1f2ba1a574db68e801323846e10d3219bf6.tar.bz2 | |
initial pass. Does not interact with the actual Dictionary yet. Issue #466
18 files changed, 346 insertions, 453 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index a1829b179..77ac7212a 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.menny.android.anysoftkeyboard"> + package="com.menny.android.anysoftkeyboard"> <supports-screens android:anyDensity="true" @@ -55,7 +55,8 @@ <!-- settings ui activities --> <!-- this is just a proxy activity, it does nothing but direct to the actual setting ativity I use this, so I can 'disable' this activity at runtime, and so remove ASK from the launcher's icons --> - <activity android:theme="@style/Theme.AskApp" + <activity + android:theme="@style/Theme.AskApp" android:name="com.menny.android.anysoftkeyboard.LauncherSettingsActivity" android:icon="@drawable/ic_launcher_settings" android:launchMode="singleTop" @@ -66,10 +67,12 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> - <activity android:theme="@style/Theme.AskApp" + <activity + android:theme="@style/Theme.AskApp" android:name="com.anysoftkeyboard.ui.settings.MainSettingsActivity" android:icon="@drawable/ic_launcher_settings" android:launchMode="singleTask" + android:windowSoftInputMode="adjustPan" android:label="@string/ime_name"> </activity> @@ -81,13 +84,15 @@ android:theme="@style/Theme.AskApp.Popup"> </activity> <!-- ui when a crash happens --> - <activity android:theme="@style/Theme.AskApp.NoTitle" + <activity + android:theme="@style/Theme.AskApp.NoTitle" android:name="com.anysoftkeyboard.ui.SendBugReportUiActivity" android:icon="@drawable/ic_launcher" android:label="@string/ime_name"> </activity> <!-- for voice --> - <service android:name="com.google.android.voiceime.ServiceHelper" /> + <service android:name="com.google.android.voiceime.ServiceHelper"/> + <activity android:name="com.google.android.voiceime.ActivityHelper" android:theme="@android:style/Theme.Translucent.NoTitleBar" diff --git a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific.java b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific.java index 89cdf9c77..2fe7a4a0d 100644 --- a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific.java +++ b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Canvas; import android.view.GestureDetector; import android.view.inputmethod.InputConnection; -import android.widget.AbsListView; import com.anysoftkeyboard.IndirectlyInstantiated; import com.anysoftkeyboard.WordComposer; @@ -28,15 +27,13 @@ import com.anysoftkeyboard.WordComposer; @IndirectlyInstantiated public interface DeviceSpecific { - public String getApiLevel(); + String getApiLevel(); - public MultiTouchSupportLevel getMultiTouchSupportLevel(Context appContext); + MultiTouchSupportLevel getMultiTouchSupportLevel(Context appContext); - public GestureDetector createGestureDetector(Context appContext, AskOnGestureListener listener); + GestureDetector createGestureDetector(Context appContext, AskOnGestureListener listener); - public void commitCorrectionToInputConnection(InputConnection ic, WordComposer word); + void commitCorrectionToInputConnection(InputConnection ic, WordComposer word); - public void performListScrollToPosition(AbsListView listView, int position); - - public boolean isHardwareAcceleratedCanvas(Canvas canvas); + boolean isHardwareAcceleratedCanvas(Canvas canvas); } diff --git a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V3.java b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V3.java index d1c84e45d..d6d46037f 100644 --- a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V3.java +++ b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V3.java @@ -22,7 +22,6 @@ import android.content.Context; import android.graphics.Canvas; import android.view.GestureDetector; import android.view.inputmethod.InputConnection; -import android.widget.AbsListView; import com.anysoftkeyboard.IndirectlyInstantiated; import com.anysoftkeyboard.WordComposer; @@ -51,11 +50,6 @@ public class DeviceSpecific_V3 implements DeviceSpecific { } @Override - public void performListScrollToPosition(AbsListView listView, int position) { - listView.setSelection(position); - } - - @Override public boolean isHardwareAcceleratedCanvas(Canvas canvas) { return false; } diff --git a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V8.java b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V8.java index 7bde76d58..c1e581f4c 100644 --- a/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V8.java +++ b/src/main/java/com/anysoftkeyboard/devicespecific/DeviceSpecific_V8.java @@ -20,7 +20,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.pm.PackageManager; import android.view.GestureDetector; -import android.widget.AbsListView; import com.anysoftkeyboard.IndirectlyInstantiated; @@ -52,9 +51,4 @@ public class DeviceSpecific_V8 extends DeviceSpecific_V7 { AskOnGestureListener listener) { return new AskV8GestureDetector(appContext, listener); } - - @Override - public void performListScrollToPosition(AbsListView listView, int position) { - listView.smoothScrollToPosition(position); - } }
\ No newline at end of file diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/AbbreviationDictionaryEditorFragment.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/AbbreviationDictionaryEditorFragment.java index 863aa450d..cfce9fd0a 100644 --- a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/AbbreviationDictionaryEditorFragment.java +++ b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/AbbreviationDictionaryEditorFragment.java @@ -7,7 +7,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import android.widget.ListAdapter; import android.widget.TextView; import com.anysoftkeyboard.dictionaries.EditableDictionary; @@ -32,60 +31,61 @@ public class AbbreviationDictionaryEditorFragment extends UserDictionaryEditorFr } @Override - protected ListAdapter getWordsListAdapter(List<UserWordsListAdapter.Word> wordsList) { - return new AbbreviationWordsListAdapter( - getActivity(), - wordsList, - this); + protected EditorWordsAdapter createAdapterForWords(List<EditorWord> wordsList) { + return new AbbreviationEditorWordsAdapter(wordsList, getActivity()); } - private static class AbbreviationWordsListAdapter extends UserWordsListAdapter { + private static class AbbreviationEditorWordsAdapter extends EditorWordsAdapter { - public AbbreviationWordsListAdapter(Context context, List<Word> words, AdapterCallbacks callbacks) { - super(context, words, callbacks); - } + private final Context mContext; - private static String getAbbreviation(@Nullable Word word) { - if (word == null) return ""; - return AbbreviationsDictionary.getAbbreviation(word.word, word.frequency); + public AbbreviationEditorWordsAdapter(List<EditorWord> editorWords, Context context) { + super(editorWords, LayoutInflater.from(context)); + mContext = context; } - private static String getExplodedSentence(@Nullable Word word) { - if (word == null) return ""; - return AbbreviationsDictionary.getExplodedSentence(word.word, word.frequency); + @Override + protected EditorWord.Editing createEmptyNewEditing() { + return new EditorWord.Editing("", 0); } - @Override - protected void updateEditedWordRow(View rootView, TextView wordView, Word word) { - wordView.setText(getAbbreviation(word)); - EditText explodedSentence = (EditText)rootView.findViewById(R.id.word_target_view); - explodedSentence.setText(getExplodedSentence(word)); + protected void bindNormalWordViewText(TextView wordView, EditorWord editorWord) { + wordView.setText(mContext.getString(R.string.abbreviation_dict_word_template, + getAbbreviation(editorWord), getExplodedSentence(editorWord))); } @Override - protected void updateNormalWordRow(View rootView, TextView wordView, Word word) { - wordView.setText(getContext().getString(R.string.abbreviation_dict_word_template, - getAbbreviation(word), getExplodedSentence(word))); + protected View inflateEditingRowView(LayoutInflater layoutInflater, ViewGroup parent) { + return layoutInflater.inflate(R.layout.abbreviation_dictionary_word_row_edit, parent, false); } @Override - protected View inflateEditedWordRow(LayoutInflater inflater, ViewGroup parent) { - return inflater.inflate(R.layout.abbreviation_dictionary_word_row_edit, parent, false); + protected void bindEditingWordViewText(EditText wordView, EditorWord editorWord) { + wordView.setText(getAbbreviation(editorWord)); + EditText explodedSentence = (EditText) ((View)wordView.getParent()).findViewById(R.id.word_target_view); + explodedSentence.setText(getExplodedSentence(editorWord)); } @Override - protected Word onWordEditApproved(View approveButton, @Nullable Word oldWord) { - View parent = ((View) approveButton.getParent()); - EditText abbreviationView = (EditText) parent.findViewById(R.id.word_view); - EditText explodedSentenceView = (EditText) parent.findViewById(R.id.word_target_view); - final String newAbbreviation = abbreviationView.getText().toString(); + protected EditorWord createNewEditorWord(EditText wordView, EditorWord oldEditorWord) { + EditText explodedSentenceView = (EditText) ((View)wordView.getParent()).findViewById(R.id.word_target_view); + final String newAbbreviation = wordView.getText().toString(); final String newExplodedSentence = explodedSentenceView.getText().toString(); if (TextUtils.isEmpty(newAbbreviation) || TextUtils.isEmpty(newExplodedSentence)) { - return null; + return oldEditorWord; } else { - return new Word(newAbbreviation+newExplodedSentence, newAbbreviation.length()); + return new EditorWord(newAbbreviation + newExplodedSentence, newAbbreviation.length()); } } - } + private static String getAbbreviation(@Nullable EditorWord word) { + if (word == null) return ""; + return AbbreviationsDictionary.getAbbreviation(word.word, word.frequency); + } + + private static String getExplodedSentence(@Nullable EditorWord word) { + if (word == null) return ""; + return AbbreviationsDictionary.getExplodedSentence(word.word, word.frequency); + } + } } diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWord.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWord.java new file mode 100644 index 000000000..227d383f0 --- /dev/null +++ b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWord.java @@ -0,0 +1,26 @@ +package com.anysoftkeyboard.ui.settings.wordseditor; + +import android.support.annotation.NonNull; + +/*package*/ class EditorWord { + @NonNull + public final String word; + public final int frequency; + + public EditorWord(@NonNull String word, int frequency) { + this.word = word; + this.frequency = frequency; + } + + public static class Editing extends EditorWord { + public Editing(@NonNull String word, int frequency) { + super(word, frequency); + } + } + + public static class AddNew extends EditorWord { + public AddNew() { + super("", -1); + } + } +} diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWordsAdapter.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWordsAdapter.java new file mode 100644 index 000000000..db49a8216 --- /dev/null +++ b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/EditorWordsAdapter.java @@ -0,0 +1,199 @@ +package com.anysoftkeyboard.ui.settings.wordseditor; + +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.menny.android.anysoftkeyboard.R; + +import java.util.ArrayList; +import java.util.List; + +public class EditorWordsAdapter extends RecyclerView.Adapter<EditorWordsAdapter.EditorWordViewHolder> { + + protected final List<EditorWord> mEditorWords; + private final LayoutInflater mLayoutInflater; + + public EditorWordsAdapter(List<EditorWord> editorWords, LayoutInflater layoutInflater) { + mEditorWords = new ArrayList<>(editorWords); + mEditorWords.add(new EditorWord.AddNew()); + mLayoutInflater = layoutInflater; + } + + @Override + public int getItemViewType(int position) { + EditorWord editorWord = mEditorWords.get(position); + if (editorWord instanceof EditorWord.Editing) { + return R.id.word_editor_view_type_editing_row; + } else if (editorWord instanceof EditorWord.AddNew) { + if (position == 0) { + return R.id.word_editor_view_type_empty_view_row; + } else { + return R.id.word_editor_view_type_add_new_row; + } + } else { + return R.id.word_editor_view_type_row; + } + } + + @Override + public EditorWordViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + switch (viewType) { + case R.id.word_editor_view_type_editing_row: + return new EditorWordViewHolderEditing(inflateEditingRowView(mLayoutInflater, parent)); + case R.id.word_editor_view_type_empty_view_row: + return new EditorWordViewHolderAddNew(mLayoutInflater.inflate(R.layout.word_editor_empty_view, parent, false)); + case R.id.word_editor_view_type_add_new_row: + return new EditorWordViewHolderAddNew(mLayoutInflater.inflate(R.layout.user_dictionary_word_row_add, parent, false)); + default: + return new EditorWordViewHolderNormal(mLayoutInflater.inflate(R.layout.user_dictionary_word_row, parent, false)); + } + } + + protected View inflateEditingRowView(LayoutInflater layoutInflater, ViewGroup parent) { + return layoutInflater.inflate(R.layout.user_dictionary_word_row_edit, parent, false); + } + + @Override + public void onBindViewHolder(EditorWordViewHolder holder, int position) { + holder.bind(mEditorWords.get(position)); + } + + @Override + public int getItemCount() { + return mEditorWords.size(); + } + + public void addNewWordAtEnd(RecyclerView wordsRecyclerView) { + final int lastLocation = mEditorWords.size() - 1; + EditorWord editorWord = mEditorWords.get(lastLocation); + if (editorWord instanceof EditorWord.AddNew) { + mEditorWords.remove(lastLocation); + } + final int newLastLocation = mEditorWords.size() - 1; + mEditorWords.add(createEmptyNewEditing()); + notifyItemChanged(newLastLocation); + wordsRecyclerView.smoothScrollToPosition(newLastLocation); + } + + protected EditorWord.Editing createEmptyNewEditing() { + return new EditorWord.Editing("", 128); + } + + protected void bindNormalWordViewText(TextView wordView, EditorWord editorWord) { + wordView.setText(editorWord.word); + } + + protected void bindEditingWordViewText(EditText wordView, EditorWord editorWord) { + wordView.setText(editorWord.word); + } + + protected EditorWord createNewEditorWord(EditText wordView, EditorWord oldEditorWord) { + return new EditorWord(wordView.getText().toString(), oldEditorWord.frequency); + } + + /*package*/ abstract class EditorWordViewHolder extends RecyclerView.ViewHolder { + private EditorWord mWord; + + public EditorWordViewHolder(View itemView) { + super(itemView); + } + + protected int getItemPosition() { + return mEditorWords.indexOf(mWord); + } + + public void bind(EditorWord editorWord) { + mWord = editorWord; + } + } + + private class EditorWordViewHolderAddNew extends EditorWordViewHolder implements View.OnClickListener { + + public EditorWordViewHolderAddNew(View itemView) { + super(itemView); + itemView.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + final int itemPosition = getItemPosition(); + mEditorWords.remove(itemPosition); + mEditorWords.add(itemPosition, createEmptyNewEditing()); + notifyItemChanged(itemPosition); + } + } + + private class EditorWordViewHolderNormal extends EditorWordViewHolder implements View.OnClickListener { + private final TextView mWordView; + + public EditorWordViewHolderNormal(View itemView) { + super(itemView); + mWordView = (TextView) itemView.findViewById(R.id.word_view); + mWordView.setOnClickListener(this); + itemView.findViewById(R.id.delete_user_word).setOnClickListener(this); + } + + @Override + public void bind(EditorWord editorWord) { + super.bind(editorWord); + bindNormalWordViewText(mWordView, editorWord); + } + + @Override + public void onClick(View v) { + final int itemPosition = getItemPosition(); + if (v == mWordView) { + EditorWord editorWord = mEditorWords.remove(itemPosition); + mEditorWords.add(itemPosition, new EditorWord.Editing(editorWord.word, editorWord.frequency)); + notifyItemChanged(itemPosition); + } else if (v.getId() == R.id.delete_user_word) { + mEditorWords.remove(itemPosition); + notifyItemRemoved(itemPosition); + } + } + } + + private class EditorWordViewHolderEditing extends EditorWordViewHolder implements View.OnClickListener { + private final EditText mWordView; + + public EditorWordViewHolderEditing(View itemView) { + super(itemView); + mWordView = (EditText) itemView.findViewById(R.id.word_view); + itemView.findViewById(R.id.approve_user_word).setOnClickListener(this); + itemView.findViewById(R.id.cancel_user_word).setOnClickListener(this); + } + + @Override + public void bind(EditorWord editorWord) { + super.bind(editorWord); + bindEditingWordViewText(mWordView, editorWord); + } + + @Override + public void onClick(View v) { + final int itemPosition = getItemPosition(); + final boolean addNewRow = (itemPosition == mEditorWords.size()-1); + if (v.getId() == R.id.cancel_user_word || TextUtils.isEmpty(mWordView.getText())) { + EditorWord editorWord = mEditorWords.remove(itemPosition); + if (addNewRow) { + mEditorWords.add(itemPosition, new EditorWord.AddNew()); + } else { + mEditorWords.add(itemPosition, new EditorWord(editorWord.word, editorWord.frequency)); + } + } else if (v.getId() == R.id.approve_user_word) { + EditorWord editorWord = mEditorWords.remove(itemPosition); + mEditorWords.add(itemPosition, createNewEditorWord(mWordView, editorWord)); + if (addNewRow) { + mEditorWords.add(new EditorWord.AddNew()); + notifyItemInserted(mEditorWords.size() - 1); + } + } + notifyItemChanged(itemPosition); + } + } +} diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java index c645823d8..e36915e04 100644 --- a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java +++ b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java @@ -23,21 +23,18 @@ import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBar; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; -import android.widget.GridView; -import android.widget.ListAdapter; -import android.widget.ListView; import android.widget.Spinner; import com.anysoftkeyboard.dictionaries.EditableDictionary; @@ -46,7 +43,6 @@ import com.anysoftkeyboard.dictionaries.WordsCursor; import com.anysoftkeyboard.keyboards.KeyboardAddOnAndBuilder; import com.anysoftkeyboard.keyboards.KeyboardFactory; import com.anysoftkeyboard.utils.Log; -import com.menny.android.anysoftkeyboard.AnyApplication; import com.menny.android.anysoftkeyboard.R; import net.evendanan.pushingpixels.AsyncTaskWithProgressWindow; @@ -59,7 +55,7 @@ import java.util.Comparator; import java.util.List; public class UserDictionaryEditorFragment extends Fragment - implements AsyncTaskWithProgressWindow.AsyncTaskOwner, AdapterView.OnItemClickListener, UserWordsListAdapter.AdapterCallbacks { + implements AsyncTaskWithProgressWindow.AsyncTaskOwner { private Dialog mDialog; @@ -79,10 +75,11 @@ public class UserDictionaryEditorFragment extends Fragment private String mSelectedLocale = null; EditableDictionary mCurrentDictionary; - AbsListView mWordsListView;//this may be either ListView or GridView (in tablets) - private static final Comparator<UserWordsListAdapter.Word> msWordsComparator = new Comparator<UserWordsListAdapter.Word>() { + RecyclerView mWordsRecyclerView; + + private static final Comparator<EditorWord> msWordsComparator = new Comparator<EditorWord>() { @Override - public int compare(UserWordsListAdapter.Word lhs, UserWordsListAdapter.Word rhs) { + public int compare(EditorWord lhs, EditorWord rhs) { return lhs.word.compareTo(rhs.word); } }; @@ -117,19 +114,9 @@ public class UserDictionaryEditorFragment extends Fragment } }); - View emptyView = view.findViewById(R.id.empty_user_dictionary); - emptyView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - createEmptyItemForAdd(); - } - }); - - mWordsListView = (AbsListView) view.findViewById(android.R.id.list); - mWordsListView.setFastScrollEnabled(true); - //this is for the "empty state" - it will allow the user to quickly add the first word. - mWordsListView.setEmptyView(emptyView); - mWordsListView.setOnItemClickListener(this); + mWordsRecyclerView = (RecyclerView) view.findViewById(R.id.words_recycler_view); + mWordsRecyclerView.setHasFixedSize(false); + mWordsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); } @Override @@ -157,12 +144,9 @@ public class UserDictionaryEditorFragment extends Fragment } private void createEmptyItemForAdd() { - UserWordsListAdapter adapter = (UserWordsListAdapter) mWordsListView.getAdapter(); + EditorWordsAdapter adapter = (EditorWordsAdapter) mWordsRecyclerView.getAdapter(); if (adapter == null || !isResumed()) return; - final int addWordItemIndex = adapter.getCount() == 0 ? 0 : adapter.getCount() - 1; - //will use smooth scrolling on API8+ - AnyApplication.getDeviceSpecific().performListScrollToPosition(mWordsListView, addWordItemIndex); - onItemClick(mWordsListView, null, addWordItemIndex, 0l); + adapter.addNewWordAtEnd(mWordsRecyclerView); } @Override @@ -275,15 +259,11 @@ public class UserDictionaryEditorFragment extends Fragment }).create(); } - private void deleteWord(String word) { - mCurrentDictionary.deleteWord(word); - } - private void fillWordsList() { Log.d(TAG, "Selected locale is " + mSelectedLocale); new UserWordsEditorAsyncTask(this) { private EditableDictionary mNewDictionary; - private List<UserWordsListAdapter.Word> mWordsList; + private List<EditorWord> mWordsList; @Override protected void onPreExecute() { @@ -306,7 +286,7 @@ public class UserDictionaryEditorFragment extends Fragment mWordsList = new ArrayList<>(mCursor.getCursor().getCount()); cursor.moveToFirst(); while (!cursor.isAfterLast()) { - UserWordsListAdapter.Word word = new UserWordsListAdapter.Word( + EditorWord word = new EditorWord( mCursor.getCurrentWord(), mCursor.getCurrentWordFrequency()); mWordsList.add(word); @@ -318,39 +298,21 @@ public class UserDictionaryEditorFragment extends Fragment } protected void applyResults(Void result, Exception backgroundException) { - ListAdapter adapter = getWordsListAdapter(mWordsList); - //AbsListView introduced the setAdapter method in API11, so I'm required to check the instance type - if (mWordsListView instanceof ListView) { - //this is NOT a redundant cast! - ((ListView)mWordsListView).setAdapter(adapter); - } else if (mWordsListView instanceof GridView) { - //this is NOT a redundant cast! - ((GridView)mWordsListView).setAdapter(adapter); - } else { - throw new ClassCastException("Unknown mWordsListView type "+mWordsListView.getClass()); - } + mWordsRecyclerView.setAdapter(createAdapterForWords(mWordsList)); } }.execute(); } - protected ListAdapter getWordsListAdapter(List<UserWordsListAdapter.Word> wordsList) { - return new UserWordsListAdapter( - getActivity(), - wordsList, - this); + protected EditorWordsAdapter createAdapterForWords(List<EditorWord> wordsList) { + return new EditorWordsAdapter(wordsList, LayoutInflater.from(getActivity())); } protected EditableDictionary getEditableDictionary(String locale) { return new UserDictionary(getActivity().getApplicationContext(), locale); } - - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - ((UserWordsListAdapter) mWordsListView.getAdapter()).onItemClicked(parent, position); - } - +/* @Override - public void onWordDeleted(final UserWordsListAdapter.Word word) { + public void onWordDeleted(final EditorWord word) { new UserWordsEditorAsyncTask(this) { @Override protected Void doAsyncTask(Void[] params) throws Exception { @@ -365,8 +327,12 @@ public class UserDictionaryEditorFragment extends Fragment }.execute(); } + private void deleteWord(String word) { + mCurrentDictionary.deleteWord(word); + } + @Override - public void onWordUpdated(final String oldWord, final UserWordsListAdapter.Word newWord) { + public void onWordUpdated(final String oldWord, final EditorWord newWord) { new UserWordsEditorAsyncTask(this) { @Override @@ -383,10 +349,5 @@ public class UserDictionaryEditorFragment extends Fragment fillWordsList(); } }.execute(); - } - - @Override - public void performDiscardEdit() { - ((UserWordsListAdapter) mWordsListView.getAdapter()).onItemClicked(mWordsListView, -1/*doesn't really matter what position it is*/); - } + }*/ } diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserWordsListAdapter.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserWordsListAdapter.java deleted file mode 100644 index c09f77e5c..000000000 --- a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserWordsListAdapter.java +++ /dev/null @@ -1,311 +0,0 @@ -package com.anysoftkeyboard.ui.settings.wordseditor; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.TextView; - -import com.menny.android.anysoftkeyboard.R; - -import java.util.List; - -/** - * List adapter to be used with the words editor fragment. - */ -class UserWordsListAdapter extends ArrayAdapter<UserWordsListAdapter.Word> implements View.OnClickListener { - - public static class Word { - @NonNull - public final String word; - public final int frequency; - - public Word(@NonNull String word, int frequency) { - this.word = word; - this.frequency = frequency; - } - - @Override - public int hashCode() { - return word.hashCode() + frequency; - } - - @Override - public String toString() { - return word; - } - - @Override - public boolean equals(Object o) { - if (o instanceof Word) { - Word otherWord = (Word) o; - return otherWord.frequency == frequency && otherWord.word.equals(word); - } else { - return false; - } - } - } - - public static interface AdapterCallbacks { - void onWordDeleted(Word word); - - void onWordUpdated(String oldWord, Word newWord); - - void performDiscardEdit(); - } - - private final LayoutInflater mInflater; - private AdapterCallbacks mCallbacksListener; - - private final int NONE_POSITION = -1; - private int mCurrentlyEditPosition = NONE_POSITION; - - private final int TYPE_NORMAL = 0; - private final int TYPE_EDIT = 1; - private final int TYPE_ADD = 2; - - public UserWordsListAdapter(Context context, List<Word> words, AdapterCallbacks callbacks) { - super(context, R.id.word_view, words); - mCallbacksListener = callbacks; - mInflater = LayoutInflater.from(context); - } - - @Override - public int getViewTypeCount() { - //one for normal, and the second type is "editing" - //it will inflate the same layout on both occasions, but will allow use to stop re-creation and re-use of the EDIT view. - //the third one is for the "add new word" - return 3; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public long getItemId(int position) { - switch (getItemViewType(position)) { - case TYPE_EDIT: - return 1; - case TYPE_ADD: - return 2; - default: - final Word word = getItem(position); - return word.hashCode(); - } - } - - @Override - public int getCount() { - final int baseCount = super.getCount(); - if (baseCount == 0 && mCurrentlyEditPosition == NONE_POSITION) - return 0;//in the case that there are no words (and not editing the first word), I have a special "empty state" - - return super.getCount() + 1;//the plus one is for the "Add new"; - } - - @Override - public int getItemViewType(int position) { - if (mCurrentlyEditPosition == position) - return TYPE_EDIT; - else if (position == super.getCount())//this is the last item, which is an "Add word" item. - return TYPE_ADD; - else - return TYPE_NORMAL; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final int viewType = getItemViewType(position); - TextView wordView; - if (convertView == null) { - switch (viewType) { - case TYPE_NORMAL: - convertView = inflateNormalWordRow(mInflater, parent); - assert convertView != null; - final View deleteButton = convertView.findViewById(R.id.delete_user_word); - deleteButton.setOnClickListener(this); - break; - case TYPE_EDIT: - convertView = inflateEditedWordRow(mInflater, parent); - assert convertView != null; - final View approveButton = convertView.findViewById(R.id.approve_user_word); - approveButton.setOnClickListener(this); - wordView = ((TextView) convertView.findViewById(R.id.word_view)); - wordView.setOnKeyListener(mOnEditBoxKeyPressedListener); - wordView.addTextChangedListener(mOnEditBoxTextChangedListener); - wordView.setOnEditorActionListener(mEditBoxActionListener); - break; - case TYPE_ADD: - convertView = inflateAddWordRow(mInflater, parent); - assert convertView != null; - break; - default: - throw new IllegalArgumentException("Unknown view type!"); - } - } - - wordView = ((TextView) convertView.findViewById(R.id.word_view)); - final Word word; - //why to check the position against the super.getCount, and not the view type? - //good question! In the state where we adding a new word, the underling array is still one short, - //so the view type will be "EDIT", but the count will still be one less. - if (position == super.getCount()) { - word = null;/*empty word at the "add new word" row*/ - } else { - word = getItem(position); - } - convertView.setTag(word); - - switch (viewType) { - case TYPE_NORMAL: - updateNormalWordRow(convertView, wordView, word); - break; - case TYPE_EDIT: - updateEditedWordRow(convertView, wordView, word); - //I want the text-box to take the focus now. - wordView.requestFocus(); - break; - } - return convertView; - } - - protected void updateEditedWordRow(View rootView, TextView wordView, Word word) { - wordView.setText(word == null? "" : word.word); - } - - protected void updateNormalWordRow(View rootView, TextView wordView, Word word) { - wordView.setText(word.word); - } - - protected View inflateAddWordRow(LayoutInflater inflater, ViewGroup parent) { - return inflater.inflate(R.layout.user_dictionary_word_row_add, parent, false); - } - - protected View inflateEditedWordRow(LayoutInflater inflater, ViewGroup parent) { - return inflater.inflate(R.layout.user_dictionary_word_row_edit, parent, false); - } - - protected View inflateNormalWordRow(LayoutInflater inflater, ViewGroup parent) { - return inflater.inflate(R.layout.user_dictionary_word_row, parent, false); - } - - public void onItemClicked(AdapterView<?> listView, int position) { - if (mCurrentlyEditPosition == NONE_POSITION && position >= 0) { - //nothing was in edit mode, so we start a new one - mCurrentlyEditPosition = position; - //see http://stackoverflow.com/a/2680077/1324235 - listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); - } else { - //there was an edit in progress. Clicking out side will cause DISCARD. - mCurrentlyEditPosition = NONE_POSITION; - //see http://stackoverflow.com/a/2680077/1324235 - listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); - listView.requestFocus(); - } - notifyDataSetChanged(); - } - - - @Override - public final void onClick(View v) { - final Word word = (Word) ((View) v.getParent()).getTag(); - switch (v.getId()) { - case R.id.delete_user_word: - onWordDeleted(word); - break; - case R.id.approve_user_word: - Word newWord = onWordEditApproved(v, word); - mCurrentlyEditPosition = NONE_POSITION; - if (newWord == null || TextUtils.isEmpty(newWord.word) || newWord.frequency == 0) { - //this is weird.. The user wanted the word to be deleted? - //why not clicking on the delete icon?! - //I'm ignoring. - notifyDataSetChanged();//reloading the list. - } else { - mCallbacksListener.onWordUpdated(word == null? "" : word.word, newWord); - } - break; - } - } - - protected void onWordDeleted(Word word) { - mCallbacksListener.onWordDeleted(word); - } - - protected Word onWordEditApproved(View approveButton, @Nullable Word oldWord) { - View parent = ((View) approveButton.getParent()); - EditText editBox = (EditText) parent.findViewById(R.id.word_view); - final String newWord = editBox.getText().toString(); - if (TextUtils.isEmpty(newWord)) { - return null; - } else { - return new Word(newWord, oldWord == null? 128 : oldWord.frequency); - } - } - - protected final View.OnKeyListener mOnEditBoxKeyPressedListener = new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - //discarded! - mCallbacksListener.performDiscardEdit(); - return true; - case KeyEvent.KEYCODE_ENTER: - EditText edit = (EditText)v; - if ((edit.getImeOptions() & EditorInfo.IME_ACTION_DONE) == EditorInfo.IME_ACTION_DONE) { - View parent = (View) v.getParent(); - View approveButton = parent.findViewById(R.id.approve_user_word); - onClick(approveButton); - } else if ((edit.getImeOptions() & EditorInfo.IME_ACTION_NEXT) == EditorInfo.IME_ACTION_NEXT) { - View nextField = edit.focusSearch(View.FOCUS_RIGHT); - if (nextField != null) - nextField.requestFocus(); - } - return true; - default: - return false; - } - } - }; - - protected final TextView.OnEditorActionListener mEditBoxActionListener = new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - View parent = (View) v.getParent(); - View approveButton = parent.findViewById(R.id.approve_user_word); - onClick(approveButton); - return true; - } - }; - - private final TextWatcher mOnEditBoxTextChangedListener = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - - } - }; - -} diff --git a/src/main/res/drawable-hdpi/ic_cancel.png b/src/main/res/drawable-hdpi/ic_cancel.png Binary files differnew file mode 100644 index 000000000..c83434042 --- /dev/null +++ b/src/main/res/drawable-hdpi/ic_cancel.png diff --git a/src/main/res/drawable-mdpi/ic_cancel.png b/src/main/res/drawable-mdpi/ic_cancel.png Binary files differnew file mode 100644 index 000000000..a674ad738 --- /dev/null +++ b/src/main/res/drawable-mdpi/ic_cancel.png diff --git a/src/main/res/drawable-xhdpi/ic_cancel.png b/src/main/res/drawable-xhdpi/ic_cancel.png Binary files differnew file mode 100644 index 000000000..a7260559a --- /dev/null +++ b/src/main/res/drawable-xhdpi/ic_cancel.png diff --git a/src/main/res/drawable-xxhdpi/ic_cancel.png b/src/main/res/drawable-xxhdpi/ic_cancel.png Binary files differnew file mode 100644 index 000000000..4258c1678 --- /dev/null +++ b/src/main/res/drawable-xxhdpi/ic_cancel.png diff --git a/src/main/res/layout/abbreviation_dictionary_word_row_edit.xml b/src/main/res/layout/abbreviation_dictionary_word_row_edit.xml index 866bc7a2b..56db7e15e 100644 --- a/src/main/res/layout/abbreviation_dictionary_word_row_edit.xml +++ b/src/main/res/layout/abbreviation_dictionary_word_row_edit.xml @@ -54,4 +54,13 @@ android:scaleType="centerInside" android:src="@drawable/ic_accept" android:background="@drawable/transparent_click_feedback_background"/> + <ImageView + android:id="@+id/cancel_user_word" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:adjustViewBounds="true" + android:scaleType="centerInside" + android:src="@drawable/ic_cancel" + android:background="@drawable/transparent_click_feedback_background"/> </LinearLayout>
\ No newline at end of file diff --git a/src/main/res/layout/user_dictionary_editor.xml b/src/main/res/layout/user_dictionary_editor.xml index e1e94b5dd..5337eb947 100644 --- a/src/main/res/layout/user_dictionary_editor.xml +++ b/src/main/res/layout/user_dictionary_editor.xml @@ -19,23 +19,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <include layout="@layout/user_dictionary_editor_abslistview" /> - - <LinearLayout - android:id="@+id/empty_user_dictionary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:padding="16dp" - android:visibility="gone" - android:background="@drawable/transparent_click_feedback_background"> - <TextView - style="@style/Ask.Text.SubTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:text="@string/user_dict_settings_empty_text" - android:drawablePadding="12dp" - android:drawableTop="@drawable/ic_large_new" /> - </LinearLayout> + <android.support.v7.widget.RecyclerView + android:id="@+id/words_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> </FrameLayout>
\ No newline at end of file diff --git a/src/main/res/layout/user_dictionary_word_row_edit.xml b/src/main/res/layout/user_dictionary_word_row_edit.xml index 91c7eb626..e1c853522 100644 --- a/src/main/res/layout/user_dictionary_word_row_edit.xml +++ b/src/main/res/layout/user_dictionary_word_row_edit.xml @@ -31,4 +31,14 @@ android:scaleType="centerInside" android:src="@drawable/ic_accept" android:background="@drawable/transparent_click_feedback_background"/> + + <ImageView + android:id="@+id/cancel_user_word" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:adjustViewBounds="true" + android:scaleType="centerInside" + android:src="@drawable/ic_cancel" + android:background="@drawable/transparent_click_feedback_background"/> </LinearLayout>
\ No newline at end of file diff --git a/src/main/res/layout/word_editor_empty_view.xml b/src/main/res/layout/word_editor_empty_view.xml new file mode 100644 index 000000000..36e6f6cd6 --- /dev/null +++ b/src/main/res/layout/word_editor_empty_view.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="16dp" + android:background="@drawable/transparent_click_feedback_background"> + + <TextView + style="@style/Ask.Text.SubTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:gravity="center" + android:text="@string/user_dict_settings_empty_text" + android:drawablePadding="12dp" + android:drawableTop="@drawable/ic_large_new"/> +</LinearLayout>
\ No newline at end of file diff --git a/src/main/res/values/ids.xml b/src/main/res/values/ids.xml index 2110702c0..1b874415d 100644 --- a/src/main/res/values/ids.xml +++ b/src/main/res/values/ids.xml @@ -9,4 +9,10 @@ <item name="keyboard_ui_handler_MSG_REMOVE_CLOSE_SUGGESTIONS_HINT" type="id" /> <item name="popup_manager_dismiss_preview_message_id" type="id" /> + + <!-- words editor view types --> + <item name="word_editor_view_type_row" type="id" /> + <item name="word_editor_view_type_editing_row" type="id" /> + <item name="word_editor_view_type_add_new_row" type="id" /> + <item name="word_editor_view_type_empty_view_row" type="id" /> </resources>
\ No newline at end of file |
