mirror of
https://github.com/recloudstream/cloudstream.git
synced 2025-05-17 19:25:55 +08:00
feat: voice search (#1623)
This commit is contained in:
@ -1,7 +1,11 @@
|
||||
package com.lagradost.cloudstream3.ui.search
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.DialogInterface
|
||||
import android.content.res.Configuration
|
||||
import android.speech.RecognizerIntent
|
||||
import android.speech.SpeechRecognizer
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
@ -21,6 +25,7 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
@ -29,6 +34,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
||||
import com.lagradost.cloudstream3.AllLanguagesName
|
||||
import com.lagradost.cloudstream3.AnimeSearchResponse
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.HomePageList
|
||||
import com.lagradost.cloudstream3.MainAPI
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
@ -69,6 +75,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
class SearchFragment : Fragment() {
|
||||
@ -99,6 +106,18 @@ class SearchFragment : Fragment() {
|
||||
private var bottomSheetDialog: BottomSheetDialog? = null
|
||||
var binding: FragmentSearchBinding? = null
|
||||
|
||||
private val speechRecognizerLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val data: Intent? = result.data
|
||||
val matches = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
|
||||
if (!matches.isNullOrEmpty()) {
|
||||
val recognizedText = matches[0]
|
||||
binding?.mainSearch?.setQuery(recognizedText, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@ -234,6 +253,25 @@ class SearchFragment : Fragment() {
|
||||
searchLoadingBar.alpha = 0f
|
||||
}
|
||||
|
||||
binding?.voiceSearch?.setOnClickListener { searchView ->
|
||||
searchView?.context?.let { ctx ->
|
||||
try {
|
||||
if (!SpeechRecognizer.isRecognitionAvailable(ctx)) {
|
||||
showToast(R.string.speech_recognition_unavailable)
|
||||
} else {
|
||||
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
|
||||
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
|
||||
putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
|
||||
putExtra(RecognizerIntent.EXTRA_PROMPT, ctx.getString(R.string.begin_speaking))
|
||||
}
|
||||
speechRecognizerLauncher.launch(intent)
|
||||
}
|
||||
} catch (_ : Throwable) {
|
||||
// launch may throw
|
||||
showToast(R.string.speech_recognition_unavailable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val searchExitIcon =
|
||||
binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||
@ -576,4 +614,4 @@ class SearchFragment : Fragment() {
|
||||
.commit()*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
9
app/src/main/res/drawable/ic_mic.xml
Normal file
9
app/src/main/res/drawable/ic_mic.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,14c1.66,0 3,-1.34 3,-3v-4c0,-1.66 -1.34,-3 -3,-3 -1.66,0 -3,1.34 -3,3v4c0,1.66 1.34,3 3,3zM19,11h-2c0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5h-2c0,3.45 2.68,6.29 6,6.92v2.08h-3v2h8v-2h-3v-2.08c3.32,-0.63 6,-3.47 6,-6.92z"/>
|
||||
</vector>
|
@ -16,78 +16,96 @@
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/main_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
android:iconifiedByDefault="false"
|
||||
android:imeOptions="actionSearch"
|
||||
|
||||
android:inputType="text"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
|
||||
android:nextFocusRight="@id/search_filter"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:paddingStart="-10dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@color/transparent"
|
||||
app:queryHint="@string/search_hint"
|
||||
app:searchIcon="@drawable/search_icon"
|
||||
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/search_loading_bar"
|
||||
style="@style/Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="-35dp"
|
||||
android:foregroundTint="@color/white"
|
||||
android:progressTint="@color/white">
|
||||
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
<!--app:queryHint="@string/search_hint"
|
||||
android:background="@color/grayBackground" @color/itemBackground
|
||||
app:searchHintIcon="@drawable/search_white"
|
||||
-->
|
||||
</androidx.appcompat.widget.SearchView>
|
||||
</FrameLayout>
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/search_filter"
|
||||
android:id="@+id/voice_search"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/main_search"
|
||||
android:nextFocusRight="@id/main_search"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:src="@drawable/ic_baseline_tune_24"
|
||||
android:src="@drawable/ic_mic"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/main_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
android:iconifiedByDefault="false"
|
||||
android:imeOptions="actionSearch"
|
||||
|
||||
android:inputType="text"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
|
||||
android:nextFocusRight="@id/search_filter"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:paddingStart="-10dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@color/transparent"
|
||||
app:queryHint="@string/search_hint"
|
||||
app:searchIcon="@drawable/search_icon"
|
||||
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/search_loading_bar"
|
||||
style="@style/Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="-35dp"
|
||||
android:foregroundTint="@color/white"
|
||||
android:progressTint="@color/white">
|
||||
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
<!--app:queryHint="@string/search_hint"
|
||||
android:background="@color/grayBackground" @color/itemBackground
|
||||
app:searchHintIcon="@drawable/search_white"
|
||||
-->
|
||||
</androidx.appcompat.widget.SearchView>
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/search_filter"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/main_search"
|
||||
android:nextFocusRight="@id/main_search"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:src="@drawable/ic_baseline_tune_24"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/tvtypes_chips_scroll"
|
||||
|
@ -17,79 +17,97 @@
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/main_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
android:iconifiedByDefault="false"
|
||||
android:imeOptions="actionSearch"
|
||||
|
||||
android:inputType="text"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
|
||||
android:nextFocusRight="@id/search_filter"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:paddingStart="-10dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@color/transparent"
|
||||
app:queryHint="@string/search_hint"
|
||||
app:searchIcon="@drawable/search_icon"
|
||||
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/search_loading_bar"
|
||||
style="@style/Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="-35dp"
|
||||
android:foregroundTint="@color/white"
|
||||
android:progressTint="@color/white">
|
||||
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
<!--app:queryHint="@string/search_hint"
|
||||
android:background="@color/grayBackground" @color/itemBackground
|
||||
app:searchHintIcon="@drawable/search_white"
|
||||
-->
|
||||
</androidx.appcompat.widget.SearchView>
|
||||
</FrameLayout>
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/search_filter"
|
||||
android:id="@+id/voice_search"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/main_search"
|
||||
android:nextFocusRight="@id/main_search"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/tvtypes_chips_scroll"
|
||||
android:tag = "@string/tv_no_focus_tag"
|
||||
android:src="@drawable/ic_baseline_tune_24"
|
||||
android:src="@drawable/ic_mic"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/main_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
android:iconifiedByDefault="false"
|
||||
android:imeOptions="actionSearch"
|
||||
|
||||
android:inputType="text"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
|
||||
android:nextFocusRight="@id/search_filter"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/search_autofit_results"
|
||||
android:paddingStart="-10dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@color/transparent"
|
||||
app:queryHint="@string/search_hint"
|
||||
app:searchIcon="@drawable/search_icon"
|
||||
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/search_loading_bar"
|
||||
style="@style/Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="-35dp"
|
||||
android:foregroundTint="@color/white"
|
||||
android:progressTint="@color/white">
|
||||
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
<!--app:queryHint="@string/search_hint"
|
||||
android:background="@color/grayBackground" @color/itemBackground
|
||||
app:searchHintIcon="@drawable/search_white"
|
||||
-->
|
||||
</androidx.appcompat.widget.SearchView>
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/search_filter"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/main_search"
|
||||
android:nextFocusRight="@id/main_search"
|
||||
android:nextFocusUp="@id/nav_rail_view"
|
||||
android:nextFocusDown="@id/tvtypes_chips_scroll"
|
||||
android:tag = "@string/tv_no_focus_tag"
|
||||
android:src="@drawable/ic_baseline_tune_24"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/tvtypes_chips_scroll"
|
||||
|
@ -115,6 +115,8 @@
|
||||
<string name="title_settings">Settings</string>
|
||||
<string name="search_hint">Search…</string>
|
||||
<string name="search_hint_site" formatted="true">Search %s…</string>
|
||||
<string name="speech_recognition_unavailable">Speech recognition is not available</string>
|
||||
<string name="begin_speaking">Begin Speaking…</string>
|
||||
<string name="no_data">No Data</string>
|
||||
<string name="episode_more_options_des">More Options</string>
|
||||
<string name="next_episode">Next episode</string>
|
||||
|
Reference in New Issue
Block a user