Commit ca27881e authored by luca020400's avatar luca020400

Jelly: Add "search in page" feature

Change-Id: I3483cf61c820683c8ae071d740deea1fc89e5c51
parent 4d40bf71
......@@ -65,6 +65,7 @@ import android.view.inputmethod.EditorInfo;
import android.webkit.CookieManager;
import android.webkit.URLUtil;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
......@@ -76,6 +77,7 @@ import org.lineageos.jelly.favorite.FavoriteActivity;
import org.lineageos.jelly.favorite.FavoriteDatabaseHandler;
import org.lineageos.jelly.history.HistoryActivity;
import org.lineageos.jelly.suggestions.SuggestionsAdapter;
import org.lineageos.jelly.ui.SearchBarController;
import org.lineageos.jelly.utils.PrefsUtils;
import org.lineageos.jelly.utils.UiUtils;
import org.lineageos.jelly.webview.WebViewCompat;
......@@ -87,7 +89,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends WebViewExtActivity implements View.OnTouchListener,
View.OnScrollChangeListener {
View.OnScrollChangeListener, SearchBarController.OnCancelListener {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String PROVIDER = "org.lineageos.jelly.fileprovider";
private static final String EXTRA_INCOGNITO = "extra_incognito";
......@@ -117,6 +119,7 @@ public class MainActivity extends WebViewExtActivity implements View.OnTouchList
private CoordinatorLayout mCoordinator;
private WebViewExt mWebView;
private ProgressBar mLoadingProgress;
private SearchBarController mSearchController;
private boolean mHasThemeColorSupport;
private Drawable mLastActionBarDrawable;
private int mThemeColor;
......@@ -221,6 +224,14 @@ public class MainActivity extends WebViewExtActivity implements View.OnTouchList
mWebView.setOnTouchListener(this);
mWebView.setOnScrollChangeListener(this);
mSearchController = new SearchBarController(mWebView,
(EditText) findViewById(R.id.search_menu_edit),
(TextView) findViewById(R.id.search_status),
(ImageButton) findViewById(R.id.search_menu_prev),
(ImageButton) findViewById(R.id.search_menu_next),
(ImageButton) findViewById(R.id.search_menu_cancel),
this);
applyThemeColor(mThemeColor);
try {
......@@ -271,6 +282,7 @@ public class MainActivity extends WebViewExtActivity implements View.OnTouchList
@Override
public void onBackPressed() {
mSearchController.onCancel();
if (mWebView.canGoBack()) {
mWebView.goBack();
} else {
......@@ -357,6 +369,10 @@ public class MainActivity extends WebViewExtActivity implements View.OnTouchList
// Delay a bit to allow popup menu hide animation to play
new Handler().postDelayed(() -> shareUrl(mWebView.getUrl()), 300);
break;
case R.id.menu_search:
// Run the search setup
showSearch();
break;
case R.id.menu_favorite:
startActivity(new Intent(this, FavoriteActivity.class));
break;
......@@ -391,6 +407,18 @@ public class MainActivity extends WebViewExtActivity implements View.OnTouchList
});
}
private void showSearch() {
findViewById(R.id.toolbar_search_bar).setVisibility(View.GONE);
findViewById(R.id.toolbar_search_page).setVisibility(View.VISIBLE);
mSearchController.onShow();
}
@Override
public void onCancelSearch() {
findViewById(R.id.toolbar_search_page).setVisibility(View.GONE);
findViewById(R.id.toolbar_search_bar).setVisibility(View.VISIBLE);
}
private void openInNewTab(String url, boolean incognito) {
Intent intent = new Intent(this, MainActivity.class);
if (url != null && !url.isEmpty()) {
......
/*
* Copyright (C) 2017 The LineageOS Project
*
* 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
* distributed under the License is distributed on an "AS IS" BASIS,
* 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 org.lineageos.jelly.ui;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import org.lineageos.jelly.utils.UiUtils;
public class SearchBarController implements
TextWatcher, TextView.OnEditorActionListener, WebView.FindListener, View.OnClickListener {
public interface OnCancelListener {
void onCancelSearch();
}
private WebView mWebView;
private EditText mEditor;
private TextView mStatus;
private ImageButton mNextButton;
private ImageButton mPrevButton;
private ImageButton mCancelButton;
private OnCancelListener mListener;
private boolean mHasStartedSearch;
private boolean mSearchDone;
private int mCurrentResultPosition;
private int mTotalResultCount;
public SearchBarController(WebView webView, EditText editor, TextView status,
ImageButton prevButton, ImageButton nextButton,
ImageButton cancelButton, OnCancelListener listener) {
mWebView = webView;
mEditor = editor;
mStatus = status;
mNextButton = nextButton;
mPrevButton = prevButton;
mCancelButton = cancelButton;
mListener = listener;
mEditor.addTextChangedListener(this);
mEditor.setOnEditorActionListener(this);
mWebView.setFindListener(this);
mPrevButton.setOnClickListener(this);
mNextButton.setOnClickListener(this);
mCancelButton.setOnClickListener(this);
}
public void onShow() {
mEditor.requestFocus();
UiUtils.showKeyboard(mEditor);
clearSearchResults();
updateNextAndPrevButtonEnabledState();
updateStatusText();
}
public void onCancel() {
mStatus.setText(null);
mWebView.clearMatches();
mListener.onCancelSearch();
}
@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) {
startSearch();
updateNextAndPrevButtonEnabledState();
}
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
UiUtils.hideKeyboard(view);
startSearch();
return true;
}
return false;
}
@Override
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
boolean isDoneCounting) {
mCurrentResultPosition = activeMatchOrdinal;
mTotalResultCount = numberOfMatches;
mSearchDone = isDoneCounting;
updateNextAndPrevButtonEnabledState();
updateStatusText();
}
@Override
public void onClick(View view) {
UiUtils.hideKeyboard(mEditor);
if (view == mCancelButton) {
onCancel();
} else if (!mHasStartedSearch) {
startSearch();
} else {
mWebView.findNext(view == mNextButton);
}
}
private void startSearch() {
String query = getQuery();
if (TextUtils.isEmpty(query)) {
clearSearchResults();
mStatus.setText(null);
} else {
mWebView.findAllAsync(query);
mHasStartedSearch = true;
mSearchDone = false;
}
updateStatusText();
}
private void clearSearchResults() {
mCurrentResultPosition = -1;
mTotalResultCount = -1;
mWebView.clearMatches();
mHasStartedSearch = false;
}
private void updateNextAndPrevButtonEnabledState() {
boolean hasText = !TextUtils.isEmpty(getQuery());
UiUtils.setImageButtonEnabled(mPrevButton,
hasText && (!mHasStartedSearch || mCurrentResultPosition > 0));
UiUtils.setImageButtonEnabled(mNextButton,
hasText && (!mHasStartedSearch || mCurrentResultPosition < (mTotalResultCount - 1)));
}
private void updateStatusText() {
if (mTotalResultCount > 0) {
mStatus.setText((mCurrentResultPosition + 1) + "/" + mTotalResultCount);
} else {
mStatus.setText(null);
}
}
private String getQuery() {
Editable s = mEditor.getText();
return s != null ? s.toString() : null;
}
}
......@@ -24,11 +24,13 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette;
import android.util.TypedValue;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
public final class UiUtils {
......@@ -104,4 +106,15 @@ public final class UiUtils {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
/**
* Sets the specified image button to the given state, while modifying or
* "graying-out" the icon as well
*
* @param enabled The state of the menu item
* @param button The menu item to modify
*/
public static void setImageButtonEnabled(ImageButton button, boolean enabled) {
button.setEnabled(enabled);
button.setAlpha(enabled ? 1.0f : 0.4f);
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 The LineageOS Project
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
distributed under the License is distributed on an "AS IS" BASIS,
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/menu_icon"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 The LineageOS Project
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
distributed under the License is distributed on an "AS IS" BASIS,
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/menu_icon"
android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 The LineageOS Project
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
distributed under the License is distributed on an "AS IS" BASIS,
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/menu_icon"
android:pathData="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" />
</vector>
\ No newline at end of file
......@@ -47,6 +47,14 @@
android:progress="54" />
<include
android:id="@+id/toolbar_search_page"
layout="@layout/search_page"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone" />
<include
android:id="@+id/toolbar_search_bar"
layout="@layout/search_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 The LineageOS Project
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
distributed under the License is distributed on an "AS IS" BASIS,
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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:paddingBottom="4dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="4dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardBackgroundColor="@color/cardview_light_background"
app:cardElevation="4dp"
app:contentPadding="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/search_menu_edit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_toStartOf="@+id/search_status"
android:background="@null"
android:fadingEdge="vertical"
android:hint="@string/search_bar_hint"
android:imeOptions="actionSearch"
android:inputType="textUri"
android:maxLines="1"
android:nextFocusLeft="@id/search_menu_edit"
android:nextFocusUp="@id/search_menu_edit"
android:paddingStart="4dp"
android:selectAllOnFocus="true"
android:textColor="@android:color/black"
android:textColorHint="@android:color/darker_gray"
tools:ignore="RtlSymmetry" />
<TextView
android:id="@id/search_status"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="16dp"
android:layout_marginStart="12dp"
android:layout_toStartOf="@+id/find_separator"
android:background="@null"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="@android:color/black"
android:textSize="12sp" />
<View
android:id="@id/find_separator"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:layout_toStartOf="@+id/search_menu_prev"
android:alpha="0.1"
android:background="#000000" />
<ImageButton
android:id="@id/search_menu_prev"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/search_menu_next"
android:adjustViewBounds="true"
android:background="?selectableItemBackgroundBorderless"
android:scaleType="center"
android:src="@drawable/ic_prev" />
<ImageButton
android:id="@id/search_menu_next"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/search_menu_cancel"
android:adjustViewBounds="true"
android:background="?selectableItemBackgroundBorderless"
android:scaleType="center"
android:src="@drawable/ic_next" />
<ImageButton
android:id="@id/search_menu_cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:adjustViewBounds="true"
android:background="?selectableItemBackgroundBorderless"
android:scaleType="center"
android:src="@drawable/ic_cancel" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
......@@ -40,6 +40,11 @@
android:icon="@drawable/ic_share"
android:title="@string/menu_share"
app:showAsAction="never" />
<item
android:id="@+id/menu_search"
android:icon="@drawable/ic_search"
android:title="@string/menu_search"
app:showAsAction="never" />
<item
android:id="@+id/menu_favorite"
android:icon="@drawable/ic_favorite"
......
......@@ -42,6 +42,8 @@
<string name="menu_desktop_mode">Switch to desktop site</string>
<!-- Menu action: enable phone mode -->
<string name="menu_mobile_mode">Switch to mobile site</string>
<!-- Menu action: search in page -->
<string name="menu_search">Find in page</string>
<!-- Share webPage: "send to" dialog title -->
<string name="share_title">Send to</string>
......@@ -172,4 +174,7 @@
<!-- Suggestions provider: no suggestions provider -->
<string name="suggestions_provider_none">None</string>
<!-- Search in page: search hint -->
<string name="search_bar_hint">Search</string>
</resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment