From 0d8d3ca81c8d953d8a6e6671f43afe9aaa45fd64 Mon Sep 17 00:00:00 2001 From: FongMi Date: Fri, 2 Sep 2022 13:56:55 +0800 Subject: [PATCH] Update Search UI --- .../tv/ui/activity/SearchActivity.java | 115 ++++++++++------- .../tv/ui/adapter/KeyboardAdapter.java | 2 +- .../android/tv/ui/custom/CustomEditText.java | 10 -- .../android/tv/ui/custom/CustomKeyboard.java | 16 +-- .../tv/ui/custom/CustomRowPresenter.java | 6 + .../tv/ui/custom/dialog/HistoryDialog.java | 5 +- .../res/drawable/ic_keyboard_space.xml | 10 -- .../res/drawable/ic_keyboard_voice.xml | 10 ++ app/src/leanback/res/drawable/ic_voice.xml | 10 -- .../leanback/res/layout/activity_search.xml | 116 +++++++++++------- .../leanback/res/layout/adapter_config.xml | 3 +- .../res/layout/adapter_keyboard_icon.xml | 2 +- .../res/layout/adapter_keyboard_text.xml | 2 +- .../leanback/res/layout/dialog_history.xml | 4 +- .../leanback/res/values-zh-rCN/strings.xml | 7 +- .../leanback/res/values-zh-rTW/strings.xml | 7 +- app/src/leanback/res/values/strings.xml | 5 +- .../fongmi/android/tv/player/ParseTask.java | 4 + 18 files changed, 195 insertions(+), 139 deletions(-) delete mode 100644 app/src/leanback/res/drawable/ic_keyboard_space.xml create mode 100644 app/src/leanback/res/drawable/ic_keyboard_voice.xml delete mode 100644 app/src/leanback/res/drawable/ic_voice.xml diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java index 33a0f63ed..cccfc8c21 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java @@ -1,7 +1,6 @@ package com.fongmi.android.tv.ui.activity; import android.Manifest; -import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; @@ -12,7 +11,6 @@ import android.speech.SpeechRecognizer; import android.text.Editable; import android.text.TextUtils; import android.view.View; -import android.view.ViewGroup; import android.view.animation.Animation; import android.view.inputmethod.EditorInfo; @@ -21,7 +19,6 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.HorizontalGridView; import androidx.leanback.widget.ItemBridgeAdapter; import androidx.viewbinding.ViewBinding; @@ -33,11 +30,13 @@ import com.fongmi.android.tv.net.Callback; import com.fongmi.android.tv.net.OKHttp; import com.fongmi.android.tv.ui.custom.CustomKeyboard; import com.fongmi.android.tv.ui.custom.CustomListener; +import com.fongmi.android.tv.ui.custom.SpaceItemDecoration; import com.fongmi.android.tv.ui.presenter.WordPresenter; import com.fongmi.android.tv.utils.ResUtil; import com.fongmi.android.tv.utils.Utils; import java.io.IOException; +import java.util.Arrays; import java.util.List; import okhttp3.Call; @@ -48,15 +47,12 @@ public class SearchActivity extends BaseActivity implements WordPresenter.OnClic private final ActivityResultLauncher launcherString = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> onVoice()); private ActivitySearchBinding mBinding; + private ArrayObjectAdapter mHistoryAdapter; private ArrayObjectAdapter mWordAdapter; private SpeechRecognizer mRecognizer; private Animation mFlicker; private Handler mHandler; - private boolean hasVoice() { - return SpeechRecognizer.isRecognitionAvailable(this); - } - public static void start(Activity activity) { activity.startActivity(new Intent(activity, SearchActivity.class)); } @@ -71,7 +67,6 @@ public class SearchActivity extends BaseActivity implements WordPresenter.OnClic mFlicker = ResUtil.getAnim(R.anim.flicker); mHandler = new Handler(Looper.getMainLooper()); mRecognizer = SpeechRecognizer.createSpeechRecognizer(this); - mBinding.voice.setVisibility(hasVoice() ? View.VISIBLE : View.GONE); CustomKeyboard.init(this, mBinding); mBinding.keyword.requestFocus(); setRecyclerView(); @@ -80,7 +75,6 @@ public class SearchActivity extends BaseActivity implements WordPresenter.OnClic @Override protected void initEvent() { - mBinding.voice.setOnClickListener(view -> onVoice()); mBinding.keyword.setOnEditorActionListener((textView, actionId, event) -> { if (actionId == EditorInfo.IME_ACTION_DONE) onSearch(); return true; @@ -95,30 +89,49 @@ public class SearchActivity extends BaseActivity implements WordPresenter.OnClic mRecognizer.setRecognitionListener(new CustomListener() { @Override public void onResults(String result) { - mBinding.voice.clearAnimation(); + stopListening(); mBinding.keyword.setText(result); mBinding.keyword.setSelection(mBinding.keyword.length()); } }); } - @SuppressLint("RestrictedApi") private void setRecyclerView() { - mBinding.word.setHorizontalSpacing(ResUtil.dp2px(16)); - mBinding.word.setRowHeight(ViewGroup.LayoutParams.WRAP_CONTENT); - mBinding.word.setFocusScrollStrategy(HorizontalGridView.FOCUS_SCROLL_ITEM); + mBinding.word.setHasFixedSize(true); + mBinding.history.setHasFixedSize(true); + mBinding.word.addItemDecoration(new SpaceItemDecoration(1, 16)); + mBinding.history.addItemDecoration(new SpaceItemDecoration(1, 16)); mBinding.word.setAdapter(new ItemBridgeAdapter(mWordAdapter = new ArrayObjectAdapter(new WordPresenter(this)))); + mBinding.history.setAdapter(new ItemBridgeAdapter(mHistoryAdapter = new ArrayObjectAdapter(new WordPresenter(this)))); + mHistoryAdapter.setItems(Arrays.asList("測試1測試1", "測試2測試2", "測試3"), null); } - private void onVoice() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { - launcherString.launch(Manifest.permission.RECORD_AUDIO); - } else { - Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); - intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); - mBinding.voice.startAnimation(mFlicker); - mRecognizer.startListening(intent); - } + private void getHot() { + mBinding.hint.setText(R.string.search_hot); + OKHttp.newCall("https://node.video.qq.com/x/api/hot_mobilesearch?channdlId=0").enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + List items = Hot.get(response.body().string()); + mHandler.post(() -> mWordAdapter.setItems(items, null)); + } + }); + } + + private void getSuggest(String text) { + mBinding.hint.setText(R.string.search_suggest); + OKHttp.newCall("https://suggest.video.iqiyi.com/?if=mobile&key=" + text).enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + List items = Suggest.get(response.body().string()); + mHandler.post(() -> mWordAdapter.setItems(items, null)); + } + }); + } + + @Override + public void onItemClick(String text) { + mBinding.keyword.setText(text); + onSearch(); } @Override @@ -136,34 +149,50 @@ public class SearchActivity extends BaseActivity implements WordPresenter.OnClic } @Override - public void onItemClick(String text) { - mBinding.keyword.setText(text); - onSearch(); + public void onVoice() { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + launcherString.launch(Manifest.permission.RECORD_AUDIO); + } else { + startListening(); + } } - private void getHot() { - OKHttp.newCall("https://node.video.qq.com/x/api/hot_mobilesearch?channdlId=0").enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - List items = Hot.get(response.body().string()); - mHandler.post(() -> mWordAdapter.setItems(items, null)); - } - }); + private void startListening() { + Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + mBinding.keyboard.setVisibility(View.INVISIBLE); + mBinding.voice.setVisibility(View.VISIBLE); + mBinding.voice.startAnimation(mFlicker); + mRecognizer.startListening(intent); } - private void getSuggest(String text) { - OKHttp.newCall("https://suggest.video.iqiyi.com/?if=mobile&key=" + text).enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - List items = Suggest.get(response.body().string()); - mHandler.post(() -> mWordAdapter.setItems(items, null)); - } - }); + private void stopListening() { + mBinding.keyboard.setVisibility(View.VISIBLE); + mBinding.voice.setVisibility(View.GONE); + mBinding.voice.clearAnimation(); + mRecognizer.stopListening(); + } + + private void destroyRecognizer() { + try { + mRecognizer.destroy(); + mRecognizer = null; + } catch (Exception ignored) { + } + } + + @Override + public void onBackPressed() { + if (mBinding.voice.getVisibility() == View.VISIBLE) { + stopListening(); + } else { + super.onBackPressed(); + } } @Override protected void onDestroy() { super.onDestroy(); - mRecognizer.destroy(); + destroyRecognizer(); } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/KeyboardAdapter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/KeyboardAdapter.java index 8ac181209..a563d8d26 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/KeyboardAdapter.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/KeyboardAdapter.java @@ -20,7 +20,7 @@ public class KeyboardAdapter extends RecyclerView.Adapter mItems; public KeyboardAdapter(OnClickListener listener) { - this.mItems = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ",", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "。", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", R.drawable.ic_keyboard_remote, "U", "V", "W", "X", "Y", "Z", R.drawable.ic_keyboard_space, R.drawable.ic_keyboard_left, R.drawable.ic_keyboard_right, R.drawable.ic_keyboard_back, R.drawable.ic_keyboard_search); + this.mItems = Arrays.asList(R.drawable.ic_keyboard_remote, R.drawable.ic_keyboard_voice, R.drawable.ic_keyboard_left, R.drawable.ic_keyboard_right, R.drawable.ic_keyboard_back, R.drawable.ic_keyboard_search, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); this.mListener = listener; } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomEditText.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomEditText.java index 8d0f54600..3992c8b94 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomEditText.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomEditText.java @@ -1,16 +1,12 @@ package com.fongmi.android.tv.ui.custom; import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Rect; import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatEditText; -import com.fongmi.android.tv.R; - public class CustomEditText extends AppCompatEditText { public CustomEditText(@NonNull Context context) { @@ -29,10 +25,4 @@ public class CustomEditText extends AppCompatEditText { public boolean isFocused() { return true; } - - @Override - protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - super.onFocusChanged(focused, direction, previouslyFocusedRect); - setBackgroundTintList(ColorStateList.valueOf(getResources().getColor(focused ? R.color.white : R.color.transparent))); - } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyboard.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyboard.java index 62fe3e567..012b2b7c4 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyboard.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyboard.java @@ -9,7 +9,7 @@ import com.fongmi.android.tv.ui.adapter.KeyboardAdapter; public class CustomKeyboard implements KeyboardAdapter.OnClickListener { private final ActivitySearchBinding binding; - private Callback callback; + private final Callback callback; public static void init(Callback callback, ActivitySearchBinding binding) { new CustomKeyboard(callback, binding).initView(); @@ -22,7 +22,7 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener { private void initView() { binding.keyboard.setHasFixedSize(true); - binding.keyboard.addItemDecoration(new SpaceItemDecoration(11, 8)); + binding.keyboard.addItemDecoration(new SpaceItemDecoration(6, 8)); binding.keyboard.setAdapter(new KeyboardAdapter(this)); } @@ -42,11 +42,6 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener { StringBuilder sb = new StringBuilder(binding.keyword.getText().toString()); int cursor = binding.keyword.getSelectionStart(); switch (resId) { - case R.drawable.ic_keyboard_space: - sb.insert(cursor, " "); - binding.keyword.setText(sb.toString()); - binding.keyword.setSelection(cursor + 1); - break; case R.drawable.ic_keyboard_left: binding.keyword.setSelection(--cursor < 0 ? 0 : cursor); break; @@ -59,6 +54,9 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener { binding.keyword.setText(sb.toString()); binding.keyword.setSelection(cursor - 1); break; + case R.drawable.ic_keyboard_voice: + callback.onVoice(); + break; case R.drawable.ic_keyboard_remote: callback.onRemote(); break; @@ -77,8 +75,10 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener { public interface Callback { - void onSearch(); + void onVoice(); void onRemote(); + + void onSearch(); } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomRowPresenter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomRowPresenter.java index 271c59ffd..d8c48a54e 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomRowPresenter.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomRowPresenter.java @@ -2,6 +2,7 @@ package com.fongmi.android.tv.ui.custom; import android.annotation.SuppressLint; +import androidx.leanback.widget.FocusHighlight; import androidx.leanback.widget.HorizontalGridView; import androidx.leanback.widget.ListRowPresenter; import androidx.leanback.widget.RowPresenter; @@ -13,6 +14,11 @@ public class CustomRowPresenter extends ListRowPresenter { private final int spacing; public CustomRowPresenter(int spacing) { + this(spacing, FocusHighlight.ZOOM_FACTOR_MEDIUM); + } + + public CustomRowPresenter(int spacing, int focusZoomFactor) { + super(focusZoomFactor); this.spacing = spacing; setShadowEnabled(false); setSelectEffectEnabled(false); diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/HistoryDialog.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/HistoryDialog.java index 627b051de..3ea36f8b9 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/HistoryDialog.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/HistoryDialog.java @@ -5,12 +5,12 @@ import android.view.LayoutInflater; import android.view.WindowManager; import androidx.appcompat.app.AlertDialog; -import androidx.recyclerview.widget.LinearLayoutManager; import com.fongmi.android.tv.bean.Config; import com.fongmi.android.tv.databinding.DialogHistoryBinding; import com.fongmi.android.tv.impl.ConfigCallback; import com.fongmi.android.tv.ui.adapter.ConfigAdapter; +import com.fongmi.android.tv.ui.custom.SpaceItemDecoration; import com.fongmi.android.tv.utils.ResUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -34,7 +34,8 @@ public class HistoryDialog implements ConfigAdapter.OnClickListener { } private void setRecyclerView() { - binding.recycler.setLayoutManager(new LinearLayoutManager(dialog.getContext())); + binding.recycler.setHasFixedSize(true); + binding.recycler.addItemDecoration(new SpaceItemDecoration(1, 16)); binding.recycler.setAdapter(adapter = new ConfigAdapter(this)); } diff --git a/app/src/leanback/res/drawable/ic_keyboard_space.xml b/app/src/leanback/res/drawable/ic_keyboard_space.xml deleted file mode 100644 index d5ff15172..000000000 --- a/app/src/leanback/res/drawable/ic_keyboard_space.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/leanback/res/drawable/ic_keyboard_voice.xml b/app/src/leanback/res/drawable/ic_keyboard_voice.xml new file mode 100644 index 000000000..a0c349844 --- /dev/null +++ b/app/src/leanback/res/drawable/ic_keyboard_voice.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/leanback/res/drawable/ic_voice.xml b/app/src/leanback/res/drawable/ic_voice.xml deleted file mode 100644 index 94172d3e5..000000000 --- a/app/src/leanback/res/drawable/ic_voice.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/leanback/res/layout/activity_search.xml b/app/src/leanback/res/layout/activity_search.xml index c4d6f66c3..88ace4952 100644 --- a/app/src/leanback/res/layout/activity_search.xml +++ b/app/src/leanback/res/layout/activity_search.xml @@ -4,70 +4,102 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center|bottom" android:keepScreenOn="true" - android:orientation="vertical"> + android:orientation="horizontal" + android:padding="24dp"> - - + android:layout_height="match_parent" + android:layout_marginEnd="24dp" + android:orientation="vertical"> + + + + + + + - + + + - + + + + + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + diff --git a/app/src/leanback/res/layout/adapter_config.xml b/app/src/leanback/res/layout/adapter_config.xml index ddc163333..5c0941d1e 100644 --- a/app/src/leanback/res/layout/adapter_config.xml +++ b/app/src/leanback/res/layout/adapter_config.xml @@ -3,8 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - android:padding="8dp"> + android:orientation="horizontal"> \ No newline at end of file + android:padding="16dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> \ No newline at end of file diff --git a/app/src/leanback/res/values-zh-rCN/strings.xml b/app/src/leanback/res/values-zh-rCN/strings.xml index d9ac2e19e..0fa30c3f7 100644 --- a/app/src/leanback/res/values-zh-rCN/strings.xml +++ b/app/src/leanback/res/values-zh-rCN/strings.xml @@ -10,9 +10,10 @@ 更新推荐 - 输入关键字… - 清空 - 远程 + 关键字… + 历史纪录 + 建议搜索 + 热门搜索 %s”的搜索结果 diff --git a/app/src/leanback/res/values-zh-rTW/strings.xml b/app/src/leanback/res/values-zh-rTW/strings.xml index 09be85a88..6fe9588f6 100644 --- a/app/src/leanback/res/values-zh-rTW/strings.xml +++ b/app/src/leanback/res/values-zh-rTW/strings.xml @@ -10,9 +10,10 @@ 更新推薦 - 輸入關鍵字… - 清除 - 遠端 + 關鍵字… + 歷史紀錄 + 建議搜尋 + 熱門搜尋 %s」的搜尋結果 diff --git a/app/src/leanback/res/values/strings.xml b/app/src/leanback/res/values/strings.xml index 930d431e6..5d48265f0 100644 --- a/app/src/leanback/res/values/strings.xml +++ b/app/src/leanback/res/values/strings.xml @@ -11,8 +11,9 @@ Keywords… - Clear - Remote + History + Suggest + Hot Search results for %s diff --git a/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java b/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java index df60e0c6d..a5af3bbc6 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java +++ b/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java @@ -47,6 +47,7 @@ public class ParseTask { if (useParse) parse = ApiConfig.get().getParse(); else if (url.startsWith("json:")) parse = Parse.get(1, url.substring(5)); else if (url.startsWith("parse:")) parse = ApiConfig.get().getParse(url.substring(6)); + else if (url.startsWith("magnet:")) parse = Parse.get(99, url); if (parse == null) parse = Parse.get(0, url); } @@ -64,6 +65,9 @@ public class ParseTask { case 3: //聚合 jsonMix(webUrl, flag); break; + case 99: //磁力 + onParseError(); + break; } }