mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 15:30:31 +05:30
search fragment + suggestion
This commit is contained in:
parent
c356f9b426
commit
21d29ad4af
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@ -5,6 +5,7 @@
|
||||
<map>
|
||||
<entry key="app/src/main/res/drawable/ic_close.xml" value="0.17135416666666667" />
|
||||
<entry key="app/src/main/res/drawable/ic_play.xml" value="0.17135416666666667" />
|
||||
<entry key="app/src/main/res/drawable/ic_search2.xml" value="0.17135416666666667" />
|
||||
<entry key="app/src/main/res/layout-land/fragment_player.xml" value="0.1" />
|
||||
<entry key="app/src/main/res/layout/activity_main.xml" value="0.1" />
|
||||
<entry key="app/src/main/res/layout/activity_player.xml" value="0.1" />
|
||||
@ -12,10 +13,12 @@
|
||||
<entry key="app/src/main/res/layout/fragment_home.xml" value="0.16" />
|
||||
<entry key="app/src/main/res/layout/fragment_library.xml" value="0.11956521739130435" />
|
||||
<entry key="app/src/main/res/layout/fragment_player.xml" value="0.1" />
|
||||
<entry key="app/src/main/res/layout/fragment_search.xml" value="0.25" />
|
||||
<entry key="app/src/main/res/layout/fragment_subscriptions.xml" value="0.1" />
|
||||
<entry key="app/src/main/res/layout/styled_quality_list.xml" value="0.15520833333333334" />
|
||||
<entry key="app/src/main/res/layout/styled_quality_list_item.xml" value="0.15520833333333334" />
|
||||
<entry key="app/src/main/res/layout/trending_row.xml" value="0.33" />
|
||||
<entry key="app/src/main/res/menu/action_bar.xml" value="0.2" />
|
||||
<entry key="app/src/main/res/menu/bottom_menu.xml" value="0.15520833333333334" />
|
||||
<entry key="app/src/main/res/xml-land/player_scene.xml" value="0.13139329805996472" />
|
||||
<entry key="app/src/main/res/xml/network_security_config.xml" value="0.15520833333333334" />
|
||||
|
@ -50,5 +50,6 @@ dependencies {
|
||||
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.0'
|
||||
|
||||
}
|
@ -3,23 +3,51 @@ package xyz.btcland.libretube
|
||||
import android.content.res.Configuration
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.FrameLayout
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.NavigationUI.onNavDestinationSelected
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
lateinit var exoPlayer:ExoPlayer
|
||||
lateinit var bottomNavigationView: BottomNavigationView
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNav)
|
||||
bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNav)
|
||||
val navController = findNavController(R.id.fragment)
|
||||
bottomNavigationView.setupWithNavController(navController)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId){
|
||||
R.id.action_search -> {
|
||||
val navController = findNavController(R.id.fragment)
|
||||
navController.popBackStack()
|
||||
navController.navigate(R.id.searchFragment)
|
||||
//bottomNavigationView.clearFocus()
|
||||
//val navController = findNavController(R.id.fragment)
|
||||
//navController.navigate(R.id.searchFragment)
|
||||
//navController.navigate(R.id.home2)
|
||||
true
|
||||
}
|
||||
R.id.action_settings -> {
|
||||
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.action_bar,menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
|
@ -12,4 +12,13 @@ interface PipedApi {
|
||||
|
||||
@GET("streams/{videoId}")
|
||||
suspend fun getStreams(@Path("videoId") videoId: String): Streams
|
||||
|
||||
@GET("search")
|
||||
suspend fun getSearchResults(
|
||||
@Query("q") searchQuery: String,
|
||||
@Query("filter") filer: String
|
||||
): List<StreamItem>
|
||||
|
||||
@GET("suggestions")
|
||||
suspend fun getSuggestions(@Query("query") query: String): List<String>
|
||||
}
|
@ -230,6 +230,7 @@ class PlayerFragment : Fragment() {
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
try {
|
||||
(activity as MainActivity).supportActionBar?.show()
|
||||
exoPlayer.stop()
|
||||
}catch (e: Exception){}
|
||||
|
||||
@ -256,135 +257,7 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun fetchJson(view: View) {
|
||||
//val client = OkHttpClient()
|
||||
|
||||
fun run() {
|
||||
/* val request = Request.Builder()
|
||||
.url("http://piped-api.alefvanoon.xyz/streams/$videoId")
|
||||
.build()
|
||||
*//* val retrofit = Retrofit.Builder()
|
||||
.baseUrl("http://piped-api.alefvanoon.xyz/")
|
||||
.addConverterFactory(JacksonConverterFactory.create())
|
||||
.build()
|
||||
|
||||
val videoInPlayer2 = retrofit.create(vidVid::class.java).vidIn(videoId)*//*
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
response.use {
|
||||
if (!response.isSuccessful) throw IOException("Unexpected code $response")
|
||||
val body = response.body!!.string()
|
||||
println(body)
|
||||
val gson = GsonBuilder().create()
|
||||
val videoInPlayer = gson.fromJson(body, VideoInPlayer::class.java)
|
||||
var videosNameArray: Array<CharSequence> = arrayOf()
|
||||
videosNameArray += "HLS"
|
||||
for (vid in videoInPlayer.videoStreams){
|
||||
val name = vid.quality +" "+ vid.format
|
||||
videosNameArray += name
|
||||
}
|
||||
runOnUiThread {
|
||||
var subtitle = mutableListOf<SubtitleConfiguration>()
|
||||
if(videoInPlayer.subtitles.isNotEmpty()){
|
||||
subtitle?.add(SubtitleConfiguration.Builder(videoInPlayer.subtitles[0].url.toUri())
|
||||
.setMimeType(videoInPlayer.subtitles[0].mimeType) // The correct MIME type (required).
|
||||
.setLanguage(videoInPlayer.subtitles[0].code) // The subtitle language (optional).
|
||||
.build())}
|
||||
val mediaItem: MediaItem = MediaItem.Builder()
|
||||
.setUri(videoInPlayer.hls)
|
||||
.setSubtitleConfigurations(subtitle)
|
||||
.build()
|
||||
exoPlayer = ExoPlayer.Builder(view.context)
|
||||
.build()
|
||||
exoPlayerView.setShowSubtitleButton(true)
|
||||
exoPlayerView.setShowNextButton(false)
|
||||
exoPlayerView.setShowPreviousButton(false)
|
||||
//exoPlayerView.controllerShowTimeoutMs = 1500
|
||||
exoPlayerView.controllerHideOnTouch = true
|
||||
exoPlayerView.player = exoPlayer
|
||||
exoPlayer.setMediaItem(mediaItem)
|
||||
///exoPlayer.getMediaItemAt(5)
|
||||
exoPlayer.prepare()
|
||||
exoPlayer.play()
|
||||
|
||||
view.findViewById<TextView>(R.id.title_textView).text = videoInPlayer.title
|
||||
|
||||
view.findViewById<ImageButton>(R.id.quality_select).setOnClickListener{
|
||||
//Dialog for quality selection
|
||||
val builder: AlertDialog.Builder? = activity?.let {
|
||||
AlertDialog.Builder(it)
|
||||
}
|
||||
builder!!.setTitle(R.string.choose_quality_dialog)
|
||||
.setItems(videosNameArray,
|
||||
DialogInterface.OnClickListener { _, which ->
|
||||
whichQuality = which
|
||||
if(videoInPlayer.subtitles.isNotEmpty()) {
|
||||
var subtitle =
|
||||
mutableListOf<SubtitleConfiguration>()
|
||||
subtitle?.add(
|
||||
SubtitleConfiguration.Builder(videoInPlayer.subtitles[0].url.toUri())
|
||||
.setMimeType(videoInPlayer.subtitles[0].mimeType) // The correct MIME type (required).
|
||||
.setLanguage(videoInPlayer.subtitles[0].code) // The subtitle language (optional).
|
||||
.build()
|
||||
)
|
||||
}
|
||||
if(which==0){
|
||||
val mediaItem: MediaItem = MediaItem.Builder()
|
||||
.setUri(videoInPlayer.hls)
|
||||
.setSubtitleConfigurations(subtitle)
|
||||
.build()
|
||||
exoPlayer.setMediaItem(mediaItem)
|
||||
}else{
|
||||
val dataSourceFactory: DataSource.Factory =
|
||||
DefaultHttpDataSource.Factory()
|
||||
val videoItem: MediaItem = MediaItem.Builder()
|
||||
.setUri(videoInPlayer.videoStreams[which-1].url)
|
||||
.setSubtitleConfigurations(subtitle)
|
||||
.build()
|
||||
val videoSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory)
|
||||
.createMediaSource(videoItem)
|
||||
var audioSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory)
|
||||
.createMediaSource(fromUri(videoInPlayer.audioStreams[0].url))
|
||||
if (videoInPlayer.videoStreams[which-1].quality=="720p" || videoInPlayer.videoStreams[which-1].quality=="1080p" || videoInPlayer.videoStreams[which-1].quality=="480p" ){
|
||||
audioSource = ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(fromUri(videoInPlayer.audioStreams[getMostBitRate(videoInPlayer.audioStreams)].url))
|
||||
//println("fuckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkitttttttttttttttttttttt")
|
||||
}
|
||||
val mergeSource: MediaSource = MergingMediaSource(videoSource,audioSource)
|
||||
exoPlayer.setMediaSource(mergeSource)
|
||||
}
|
||||
view.findViewById<TextView>(R.id.quality_text).text=videosNameArray[which]
|
||||
})
|
||||
val dialog: AlertDialog? = builder?.create()
|
||||
dialog?.show()
|
||||
}
|
||||
//Listener for play and pause icon change
|
||||
exoPlayer!!.addListener(object : com.google.android.exoplayer2.Player.Listener {
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean,playbackState: Int) {
|
||||
if (playWhenReady && playbackState == Player.STATE_READY) {
|
||||
// media actually playing
|
||||
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_pause)
|
||||
} else if (playWhenReady) {
|
||||
// might be idle (plays after prepare()),
|
||||
// buffering (plays when data available)
|
||||
// or ended (plays when seek away from end)
|
||||
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_play)
|
||||
} else {
|
||||
// player paused in any state
|
||||
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_play)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
})*/
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getStreams(videoId!!)
|
||||
|
123
app/src/main/java/xyz/btcland/libretube/SearchFragment.kt
Normal file
123
app/src/main/java/xyz/btcland/libretube/SearchFragment.kt
Normal file
@ -0,0 +1,123 @@
|
||||
package xyz.btcland.libretube
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
private const val ARG_PARAM1 = "param1"
|
||||
private const val ARG_PARAM2 = "param2"
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* Use the [SearchFragment.newInstance] factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
class SearchFragment : Fragment() {
|
||||
// TODO: Rename and change types of parameters
|
||||
private var param1: String? = null
|
||||
private var param2: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
param1 = it.getString(ARG_PARAM1)
|
||||
param2 = it.getString(ARG_PARAM2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_search, container, false)
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val autoTextView = view.findViewById<AutoCompleteTextView>(R.id.autoCompleteTextView)
|
||||
autoTextView.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
count: Int,
|
||||
after: Int
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
if(s!! != ""){
|
||||
println(s.toString())
|
||||
fetchSuggestions(s.toString(), autoTextView)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun fetchSuggestions(query: String, autoTextView: AutoCompleteTextView){
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSuggestions(query)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
}
|
||||
val adapter = ArrayAdapter(context!!, android.R.layout.simple_list_item_1, response)
|
||||
autoTextView.setAdapter(adapter)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param param1 Parameter 1.
|
||||
* @param param2 Parameter 2.
|
||||
* @return A new instance of fragment SearchFragment.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
@JvmStatic
|
||||
fun newInstance(param1: String, param2: String) =
|
||||
SearchFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(ARG_PARAM1, param1)
|
||||
putString(ARG_PARAM2, param2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||
this ?: return
|
||||
if (!isAdded) return // Fragment not attached to an Activity
|
||||
activity?.runOnUiThread(action)
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package xyz.btcland.libretube.obj;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Playlist {
|
||||
|
||||
public String name, thumbnailUrl, bannerUrl, nextpage, uploader, uploaderUrl, uploaderAvatar;
|
||||
public int videos;
|
||||
public List<StreamItem> relatedStreams;
|
||||
|
||||
public Playlist(String name, String thumbnailUrl, String bannerUrl, String nextpage, String uploader,
|
||||
String uploaderUrl, String uploaderAvatar, int videos, List<StreamItem> relatedStreams) {
|
||||
this.name = name;
|
||||
this.thumbnailUrl = thumbnailUrl;
|
||||
this.bannerUrl = bannerUrl;
|
||||
this.nextpage = nextpage;
|
||||
this.videos = videos;
|
||||
this.uploader = uploader;
|
||||
this.uploaderUrl = uploaderUrl;
|
||||
this.uploaderAvatar = uploaderAvatar;
|
||||
this.relatedStreams = relatedStreams;
|
||||
}
|
||||
}
|
13
app/src/main/java/xyz/btcland/libretube/obj/Playlist.kt
Normal file
13
app/src/main/java/xyz/btcland/libretube/obj/Playlist.kt
Normal file
@ -0,0 +1,13 @@
|
||||
package xyz.btcland.libretube.obj
|
||||
|
||||
data class Playlist(
|
||||
var name: String? = null,
|
||||
var thumbnailUrl: String? = null,
|
||||
var bannerUrl: String? = null,
|
||||
var nextpage: String? = null,
|
||||
var uploader: String? = null,
|
||||
var uploaderUrl: String? = null,
|
||||
var uploaderAvatar: String? = null,
|
||||
var videos: Int = 0,
|
||||
var relatedStreams: List<StreamItem?>? = null,
|
||||
)
|
@ -1,5 +1,15 @@
|
||||
package xyz.btcland.libretube.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo
|
||||
import xyz.btcland.libretube.obj.search.SearchChannel
|
||||
import xyz.btcland.libretube.obj.search.SearchPlaylist
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
|
||||
@JsonSubTypes(value =[
|
||||
JsonSubTypes.Type(SearchChannel::class),
|
||||
JsonSubTypes.Type(SearchPlaylist::class)
|
||||
])
|
||||
data class StreamItem(
|
||||
var url: String?,
|
||||
var title: String?,
|
||||
|
@ -0,0 +1,11 @@
|
||||
package xyz.btcland.libretube.obj.search
|
||||
|
||||
data class SearchChannel(
|
||||
var name: String? = null,
|
||||
var thumbnail: String? = null,
|
||||
var url: String? = null,
|
||||
var description: String? = null,
|
||||
var subscribers: Long? = -1,
|
||||
var videos: Long? = -1,
|
||||
var verified: Boolean? = null
|
||||
)
|
@ -0,0 +1,10 @@
|
||||
package xyz.btcland.libretube.obj.search
|
||||
|
||||
data class SearchPlaylist(
|
||||
var name: String? = null,
|
||||
var thumbnail: String? = null,
|
||||
var url: String? = null,
|
||||
var uploaderName: String? =null,
|
||||
var videos: Long = -1
|
||||
|
||||
)
|
5
app/src/main/res/drawable/ic_search.xml
Normal file
5
app/src/main/res/drawable/ic_search.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_search2.xml
Normal file
10
app/src/main/res/drawable/ic_search2.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="35dp"
|
||||
android:height="35dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_settings.xml
Normal file
5
app/src/main/res/drawable/ic_settings.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
45
app/src/main/res/layout/fragment_search.xml
Normal file
45
app/src/main/res/layout/fragment_search.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
|
||||
tools:context=".SearchFragment">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/autoCompleteTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:hint="@string/search_hint"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:minHeight="48dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/imageView_Search"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_Search"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="7dp"
|
||||
android:src="@drawable/ic_search2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/autoCompleteTextView" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
15
app/src/main/res/menu/action_bar.xml
Normal file
15
app/src/main/res/menu/action_bar.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:title="Search"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:id="@+id/action_search"
|
||||
app:showAsAction="always"
|
||||
/>
|
||||
<item android:title="Settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:id="@+id/action_settings"
|
||||
app:showAsAction="ifRoom"
|
||||
/>
|
||||
</menu>
|
@ -4,5 +4,6 @@
|
||||
<item android:id="@+id/home2" android:title="Home" android:icon="@drawable/ic_home"/>
|
||||
<item android:id="@+id/subscriptions" android:title="Subscriptions" android:icon="@drawable/ic_subscriptions"/>
|
||||
<item android:id="@+id/library" android:title="Library" android:icon="@drawable/ic_library"/>
|
||||
<item android:id="@+id/searchFragment" android:visible="false"/>
|
||||
|
||||
</menu>
|
@ -9,15 +9,32 @@
|
||||
android:id="@+id/home2"
|
||||
android:name="xyz.btcland.libretube.Home"
|
||||
android:label="fragment_home"
|
||||
tools:layout="@layout/fragment_home" />
|
||||
tools:layout="@layout/fragment_home" >
|
||||
<action
|
||||
android:id="@+id/action_home2_to_searchFragment"
|
||||
app:destination="@id/searchFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/subscriptions"
|
||||
android:name="xyz.btcland.libretube.Subscriptions"
|
||||
android:label="fragment_subscriptions"
|
||||
tools:layout="@layout/fragment_subscriptions" />
|
||||
tools:layout="@layout/fragment_subscriptions" >
|
||||
<action
|
||||
android:id="@+id/action_subscriptions_to_searchFragment"
|
||||
app:destination="@id/searchFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/library"
|
||||
android:name="xyz.btcland.libretube.Library"
|
||||
android:label="fragment_library"
|
||||
tools:layout="@layout/fragment_library" />
|
||||
tools:layout="@layout/fragment_library" >
|
||||
<action
|
||||
android:id="@+id/action_library_to_searchFragment"
|
||||
app:destination="@id/searchFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/searchFragment"
|
||||
android:name="xyz.btcland.libretube.SearchFragment"
|
||||
android:label="fragment_search"
|
||||
tools:layout="@layout/fragment_search" />
|
||||
</navigation>
|
@ -1,6 +1,7 @@
|
||||
<resources>
|
||||
<string name="app_name">LibreTube</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
<string name="choose_quality_dialog">Choose Quality:</string>
|
||||
<string name="search_hint">Search</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user