diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java index c4be3aaac..0499cd55f 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java @@ -24,6 +24,7 @@ import com.hippo.ehviewer.R; import com.hippo.ehviewer.ui.ContentActivity; import com.hippo.ehviewer.widget.ContentLayout; import com.hippo.ehviewer.widget.SearchBar; +import com.hippo.ehviewer.widget.SearchDatabase; import com.hippo.scene.Scene; import com.hippo.scene.TransitionCurtain; import com.hippo.util.Log; @@ -37,6 +38,7 @@ class GalleryListScene extends Scene implements SearchBar.Helper{ private ContentActivity mActivity; private Resources mResources; + private SearchDatabase mSearchDatabase; private SearchBar mSearchBar; private ContentLayout mContentLayout; @@ -48,6 +50,7 @@ class GalleryListScene extends Scene implements SearchBar.Helper{ mActivity = (ContentActivity) getStageActivity(); mResources = mActivity.getResources(); + mSearchDatabase = SearchDatabase.getInstance(getStageActivity()); mSearchBar = (SearchBar) findViewById(R.id.search_bar); mContentLayout = (ContentLayout) findViewById(R.id.content_layout); @@ -73,6 +76,7 @@ class GalleryListScene extends Scene implements SearchBar.Helper{ }, 1000); } + @Override protected void onGetFitPaddingBottom(int b) { // TODO } @@ -90,5 +94,7 @@ class GalleryListScene extends Scene implements SearchBar.Helper{ @Override public void onApplySearch(String query) { Log.d("onApplySearch " + query); + mSearchDatabase.addQuery(query); + mSearchBar.setInNormalMode(); } } diff --git a/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java b/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java index 6c581cbcc..cf8856946 100644 --- a/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java +++ b/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java @@ -21,11 +21,12 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; -import android.graphics.Typeface; import android.os.Build; import android.support.annotation.NonNull; import android.support.v7.widget.CardView; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -49,7 +50,7 @@ import java.util.ArrayList; import java.util.List; public class SearchBar extends CardView implements View.OnClickListener, - TextView.OnEditorActionListener { + TextView.OnEditorActionListener, TextWatcher { private static final long ANIMATION_TIME = 300; @@ -60,7 +61,7 @@ public class SearchBar extends CardView implements View.OnClickListener, private float mProgress; private SimpleImageView mMenuButton; - private TextView mLogoTextView; + private TextView mTitleTextView; private SimpleImageView mActionButton; private SearchEditText mEditText; private ListView mList; @@ -68,6 +69,7 @@ public class SearchBar extends CardView implements View.OnClickListener, private DrawerArrowDrawable mDrawerArrowDrawable; private AddDeleteDrawable mAddDeleteDrawable; + private SearchDatabase mSearchDatabase; private List mSuggestionList; private ArrayAdapter mSuggestionAdapter; @@ -93,15 +95,17 @@ public class SearchBar extends CardView implements View.OnClickListener, } private void init(Context context) { + mSearchDatabase = SearchDatabase.getInstance(getContext()); + setRadius(UiUtils.dp2pix(context, 2)); setCardElevation(UiUtils.dp2pix(context, 2)); setCardBackgroundColor(Color.WHITE); setOnClickListener(this); LayoutInflater.from(context).inflate(R.layout.widget_search_bar, this); - mMenuButton = (SimpleImageView) findViewById(R.id.menu); - mLogoTextView = (TextView) findViewById(R.id.logo); - mActionButton = (SimpleImageView) findViewById(R.id.action); + mMenuButton = (SimpleImageView) findViewById(R.id.search_menu); + mTitleTextView = (TextView) findViewById(R.id.search_title); + mActionButton = (SimpleImageView) findViewById(R.id.search_action); mEditText = (SearchEditText) findViewById(R.id.search_edit_text); mList = (ListView) findViewById(R.id.search_bar_list); @@ -110,22 +114,28 @@ public class SearchBar extends CardView implements View.OnClickListener, mMenuButton.setDrawable(mDrawerArrowDrawable); mMenuButton.setOnClickListener(this); - mLogoTextView.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/Slabo.ttf")); mActionButton.setDrawable(mAddDeleteDrawable); mActionButton.setOnClickListener(this); mEditText.setSearchBar(this); mEditText.setOnEditorActionListener(this); + mEditText.addTextChangedListener(this); mSuggestionList = new ArrayList<>(); - mSuggestionList.add("aaaaaaaaaaaaaaaaaaaaa"); - mSuggestionList.add("dfsgfewrewfes"); - mSuggestionList.add("dehyklrthrhbdsrf"); - mSuggestionList.add("粉色热污染份额为别人的"); mSuggestionAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, mSuggestionList); mList.setAdapter(mSuggestionAdapter); } + private void updateSuggestions() { + String prefix = mEditText.getText().toString(); + String[] suggestions = mSearchDatabase.getSuggestions(prefix); + mSuggestionList.clear(); + for (String suggestion : suggestions) { + mSuggestionList.add(suggestion); + } + mSuggestionAdapter.notifyDataSetChanged(); + } + public void setHelper(Helper helper) { mHelper = helper; } @@ -142,7 +152,6 @@ public class SearchBar extends CardView implements View.OnClickListener, } } else if (v == mActionButton) { if (mInEditMode) { - // TODO when set prefix mEditText.setText(""); } else { mHelper.onClickAction(); @@ -168,12 +177,14 @@ public class SearchBar extends CardView implements View.OnClickListener, if (!mInEditMode) { mInEditMode = true; setClickable(false); - ViewUtils.setVisibility(mLogoTextView, View.GONE); + ViewUtils.setVisibility(mTitleTextView, View.GONE); ViewUtils.setVisibility(mEditText, View.VISIBLE); mEditText.requestFocus(); // show ime InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + // update suggestion + updateSuggestions(); // start animator ObjectAnimator oa1 = ObjectAnimator.ofFloat(mDrawerArrowDrawable, "progress", 0f, 1f); oa1.setDuration(ANIMATION_TIME); @@ -208,7 +219,7 @@ public class SearchBar extends CardView implements View.OnClickListener, if (mInEditMode) { mInEditMode = false; setOnClickListener(this); - ViewUtils.setVisibility(mLogoTextView, View.VISIBLE); + ViewUtils.setVisibility(mTitleTextView, View.VISIBLE); ViewUtils.setVisibility(mEditText, View.GONE); // hide ime InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); @@ -243,6 +254,10 @@ public class SearchBar extends CardView implements View.OnClickListener, } } + public void setTitle(String title) { + mTitleTextView.setText(title); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -282,6 +297,21 @@ public class SearchBar extends CardView implements View.OnClickListener, } } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Empty + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Empty + } + + @Override + public void afterTextChanged(Editable s) { + updateSuggestions(); + } + public interface Helper { void onClickMenu(); void onClickAction(); diff --git a/app/src/main/java/com/hippo/ehviewer/widget/SearchDatabase.java b/app/src/main/java/com/hippo/ehviewer/widget/SearchDatabase.java new file mode 100644 index 000000000..5db8c05ea --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/widget/SearchDatabase.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2015 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.widget; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.text.TextUtils; + +import com.hippo.util.Log; + +import java.util.LinkedList; +import java.util.List; + +public class SearchDatabase { + + private static final String TAG = SearchDatabase.class.getSimpleName(); + + public static final String COLUMN_QUERY = "query"; + public static final String COLUMN_DATE = "date"; + + private static final String DATABASE_NAME = "search_database.db"; + private static final String TABLE_SUGGESTIONS = "suggestions"; + + private static final int MAX_HISTORY = 100; + + private SQLiteDatabase mDatabase; + + private static SearchDatabase sInstance; + + public static SearchDatabase getInstance(Context context) { + if (sInstance == null) { + sInstance = new SearchDatabase(context.getApplicationContext()); + } + return sInstance; + } + + private SearchDatabase(Context context) { + DatabaseHelper databaseHelper = new DatabaseHelper(context); + mDatabase = databaseHelper.getWritableDatabase(); + } + + public String[] getSuggestions(String prefix) { + List queryList = new LinkedList<>(); + + // TODO add limit + StringBuilder sb = new StringBuilder(); + sb.append("SELECT * FROM ").append(TABLE_SUGGESTIONS); + if (!TextUtils.isEmpty(prefix)) { + sb.append(" WHERE ").append(COLUMN_QUERY).append(" LIKE '") + .append(prefix).append("%'"); + } + sb.append(" ORDER BY ").append(COLUMN_DATE).append(" DESC") + .append(" LIMIT 5"); + Cursor cursor = mDatabase.rawQuery(sb.toString(), null); + int queryIndex = cursor.getColumnIndex(COLUMN_QUERY); + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String suggestion = cursor.getString(queryIndex); + if (!prefix.equals(suggestion)) { + queryList.add(suggestion); + } + cursor.moveToNext(); + } + } + cursor.close(); + return queryList.toArray(new String[queryList.size()]); + } + + public void addQuery(final String query) { + if (!TextUtils.isEmpty(query)) { + // Delete old first + deleteQuery(query); + // Add it to database + ContentValues values = new ContentValues(); + values.put(COLUMN_QUERY, query); + values.put(COLUMN_DATE, System.currentTimeMillis()); + mDatabase.insert(TABLE_SUGGESTIONS, null, values); + // Remove history if more than max + truncateHistory(MAX_HISTORY); + } + } + + public void deleteQuery(final String query) { + mDatabase.delete(TABLE_SUGGESTIONS, COLUMN_DATE + "=?", new String[]{query}); + } + + public void clearQuery() { + truncateHistory(0); + } + + /** + * Reduces the length of the history table, to prevent it from growing too large. + * + * @param maxEntries Max entries to leave in the table. 0 means remove all entries. + */ + protected void truncateHistory(int maxEntries) { + if (maxEntries < 0) { + throw new IllegalArgumentException(); + } + + try { + // null means "delete all". otherwise "delete but leave n newest" + String selection = null; + if (maxEntries > 0) { + selection = "_id IN " + + "(SELECT _id FROM " + TABLE_SUGGESTIONS + + " ORDER BY " + COLUMN_DATE + " DESC" + + " LIMIT -1 OFFSET " + String.valueOf(maxEntries) + ")"; + } + mDatabase.delete(TABLE_SUGGESTIONS, selection, null); + } catch (RuntimeException e) { + Log.e(TAG, "truncateHistory", e); + } + } + + + /** + * Builds the database. This version has extra support for using the version field + * as a mode flags field, and configures the database columns depending on the mode bits + * (features) requested by the extending class. + */ + private static class DatabaseHelper extends SQLiteOpenHelper { + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, 1); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_SUGGESTIONS + " (" + + "_id INTEGER PRIMARY KEY" + + "," + COLUMN_QUERY + " TEXT" + + "," + COLUMN_DATE + " LONG" + + ");"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_SUGGESTIONS); + onCreate(db); + } + } +} diff --git a/app/src/main/java/com/hippo/util/TextUtils.java b/app/src/main/java/com/hippo/util/TextUtils.java deleted file mode 100644 index 94103b116..000000000 --- a/app/src/main/java/com/hippo/util/TextUtils.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.util; - -public class TextUtils { - - public static final String STRING_EMPTY = ""; - public static final String STRING_NULL = "null"; - -} diff --git a/app/src/main/res/layout/widget_search_bar.xml b/app/src/main/res/layout/widget_search_bar.xml index 1419d2a98..33f128c39 100644 --- a/app/src/main/res/layout/widget_search_bar.xml +++ b/app/src/main/res/layout/widget_search_bar.xml @@ -27,7 +27,7 @@ android:layout_height="56dp">