Merge branch 'master' into import-fix

This commit is contained in:
Farbod 2022-04-17 17:44:06 +04:30 committed by GitHub
commit fd9a07bef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 277 additions and 95 deletions

View File

@ -47,7 +47,9 @@ android {
} }
} }
packagingOptions { packagingOptions {
exclude 'lib/armeabi-v7a/*_neon.so' jniLibs {
excludes += ['lib/armeabi-v7a/*_neon.so']
}
} }
} }
@ -56,9 +58,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'com.google.android.material:material:1.6.0-alpha02' implementation 'com.google.android.material:material:1.6.0-beta01'
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' implementation 'androidx.navigation:navigation-fragment-ktx:2.4.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' implementation 'androidx.navigation:navigation-ui-ktx:2.4.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.preference:preference-ktx:1.2.0' implementation 'androidx.preference:preference-ktx:1.2.0'
@ -77,5 +79,11 @@ dependencies {
implementation 'com.arthenica:ffmpeg-kit-min:4.5.1.LTS' implementation 'com.arthenica:ffmpeg-kit-min:4.5.1.LTS'
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'com.google.android.exoplayer:extension-cronet:2.17.1'
implementation 'org.chromium.net:cronet-embedded:98.4758.101'
implementation 'com.blankj:utilcode:1.30.0'
} }

View File

@ -19,22 +19,21 @@ class CreatePlaylistDialog : DialogFragment() {
// Get the layout inflater // Get the layout inflater
val inflater = requireActivity().layoutInflater; val inflater = requireActivity().layoutInflater;
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
val token = sharedPref?.getString("token", "") val token = sharedPref?.getString("token","")
Log.e("dafaq", token!!) var view: View = inflater.inflate(R.layout.dialog_createplaylist, null)
Log.e("dafaq",token!!)
assert(token != "") if(token!=""){
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE) val user = sharedPref2?.getString("username","")
val user = sharedPref2?.getString("username", "") view.findViewById<TextView>(R.id.user).text = view.findViewById<TextView>(R.id.user).text.toString()+" ("+user+")"
val view: View = inflater.inflate(R.layout.dialog_logout, null) view.findViewById<Button>(R.id.logout).setOnClickListener {
view.findViewById<TextView>(R.id.user).text = Toast.makeText(context,R.string.loggedout, Toast.LENGTH_SHORT).show()
view.findViewById<TextView>(R.id.user).text.toString() + " (" + user + ")" val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
view.findViewById<Button>(R.id.logout).setOnClickListener { with (sharedPref!!.edit()) {
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show() putString("token","")
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) apply()
with(sharedPref!!.edit()) { }
putString("token", "") dialog?.dismiss()
apply()
} }
dialog?.dismiss() dialog?.dismiss()
} }

View File

@ -7,10 +7,7 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.*
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -19,6 +16,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.github.libretube.adapters.ChannelAdapter import com.github.libretube.adapters.ChannelAdapter
import com.github.libretube.adapters.PlaylistsAdapter import com.github.libretube.adapters.PlaylistsAdapter
import com.github.libretube.adapters.SubscriptionAdapter import com.github.libretube.adapters.SubscriptionAdapter
import com.github.libretube.obj.Playlists
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import retrofit2.HttpException import retrofit2.HttpException
import java.io.IOException import java.io.IOException
@ -61,6 +59,19 @@ class Library : Fragment() {
Log.d(TAG,"hmm") Log.d(TAG,"hmm")
fetchPlaylists(view) fetchPlaylists(view)
} }
val playlistName = view.findViewById<EditText>(R.id.playlists_name)
view.findViewById<Button>(R.id.create_playlist).setOnClickListener {
if(playlistName.text.toString()!="") createPlaylist(playlistName.text.toString(),view)
}
} else{
with(view.findViewById<ImageView>(R.id.boogh2)){
visibility=View.VISIBLE
setImageResource(R.drawable.ic_login)
}
with(view.findViewById<TextView>(R.id.textLike2)){
visibility=View.VISIBLE
text = getString(R.string.please_login)
}
} }
} }
@ -114,14 +125,14 @@ class Library : Fragment() {
fun run() { fun run() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val response = try { val response = try {
RetrofitInstance.api.createPlaylist(token, name) RetrofitInstance.api.createPlaylist(token, Playlists(name = name))
}catch(e: IOException) { }catch(e: IOException) {
println(e) println(e)
Log.e(TAG, "IOException, you might not have internet connection") Log.e(TAG, "IOException, you might not have internet connection")
Toast.makeText(context,R.string.unknown_error, Toast.LENGTH_SHORT).show() Toast.makeText(context,R.string.unknown_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated return@launchWhenCreated
} catch (e: HttpException) { } catch (e: HttpException) {
Log.e(TAG, "HttpException, unexpected response") Log.e(TAG, "HttpException, unexpected response $e")
Toast.makeText(context,R.string.server_error, Toast.LENGTH_SHORT).show() Toast.makeText(context,R.string.server_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated return@launchWhenCreated
} }

View File

@ -62,7 +62,7 @@ interface PipedApi {
suspend fun deletePlaylist(@Header("Authorization") token: String, @Body playlistId: PlaylistId): Message suspend fun deletePlaylist(@Header("Authorization") token: String, @Body playlistId: PlaylistId): Message
@POST("user/playlists/create") @POST("user/playlists/create")
suspend fun createPlaylist(@Header("Authorization") token: String, @Body name: String): PlaylistId suspend fun createPlaylist(@Header("Authorization") token: String, @Body name: Playlists): PlaylistId
//only for fetching servers list //only for fetching servers list
@GET @GET

View File

@ -40,21 +40,27 @@ import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MediaItem.SubtitleConfiguration import com.google.android.exoplayer2.MediaItem.SubtitleConfiguration
import com.google.android.exoplayer2.MediaItem.fromUri import com.google.android.exoplayer2.MediaItem.fromUri
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.ext.cronet.CronetDataSource
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
import com.google.android.exoplayer2.source.MediaSource import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.MergingMediaSource import com.google.android.exoplayer2.source.MergingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.StyledPlayerView import com.google.android.exoplayer2.ui.StyledPlayerView
import com.google.android.exoplayer2.upstream.DataSource import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultDataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import org.chromium.net.CronetEngine
import retrofit2.HttpException import retrofit2.HttpException
import java.io.IOException import java.io.IOException
import java.net.URLEncoder import java.net.URLEncoder
import java.util.concurrent.Executors
import kotlin.math.abs import kotlin.math.abs
var isFullScreen = false var isFullScreen = false
class PlayerFragment : Fragment() { class PlayerFragment : Fragment() {
private val TAG = "PlayerFragment" private val TAG = "PlayerFragment"
@ -113,9 +119,15 @@ class PlayerFragment : Fragment() {
) { ) {
} }
override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float) { override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
val mainMotionLayout = mainActivity.findViewById<MotionLayout>(R.id.mainMotionLayout) val mainMotionLayout =
mainActivity.findViewById<MotionLayout>(R.id.mainMotionLayout)
mainMotionLayout.progress = abs(progress) mainMotionLayout.progress = abs(progress)
eId = endId eId = endId
sId = startId sId = startId
@ -124,7 +136,8 @@ class PlayerFragment : Fragment() {
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) { override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
println(currentId) println(currentId)
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
val mainMotionLayout = mainActivity.findViewById<MotionLayout>(R.id.mainMotionLayout) val mainMotionLayout =
mainActivity.findViewById<MotionLayout>(R.id.mainMotionLayout)
if (currentId == eId) { if (currentId == eId) {
view.findViewById<ImageButton>(R.id.quality_select).visibility = View.GONE view.findViewById<ImageButton>(R.id.quality_select).visibility = View.GONE
view.findViewById<ImageButton>(R.id.close_imageButton).visibility = View.GONE view.findViewById<ImageButton>(R.id.close_imageButton).visibility = View.GONE
@ -195,8 +208,8 @@ class PlayerFragment : Fragment() {
view.findViewById<LinearLayout>(R.id.linLayout).visibility = View.GONE view.findViewById<LinearLayout>(R.id.linLayout).visibility = View.GONE
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
isFullScreen=true isFullScreen = true
}else{ } else {
with(motionLayout) { with(motionLayout) {
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0) getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
enableTransition(R.id.yt_transition, true) enableTransition(R.id.yt_transition, true)
@ -209,7 +222,8 @@ class PlayerFragment : Fragment() {
} }
} }
relatedRecView = view.findViewById(R.id.player_recView) relatedRecView = view.findViewById(R.id.player_recView)
relatedRecView.layoutManager = GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items)) relatedRecView.layoutManager =
GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items))
} }
override fun onStop() { override fun onStop() {
@ -220,7 +234,8 @@ class PlayerFragment : Fragment() {
super.onDestroy() super.onDestroy()
try { try {
exoPlayer.stop() exoPlayer.stop()
} catch (e: Exception) {} } catch (e: Exception) {
}
} }
private fun fetchJson(view: View) { private fun fetchJson(view: View) {
@ -231,11 +246,11 @@ class PlayerFragment : Fragment() {
} catch (e: IOException) { } catch (e: IOException) {
println(e) println(e)
Log.e(TAG, "IOException, you might not have internet connection") Log.e(TAG, "IOException, you might not have internet connection")
Toast.makeText(context,R.string.unknown_error, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated return@launchWhenCreated
} catch (e: HttpException) { } catch (e: HttpException) {
Log.e(TAG, "HttpException, unexpected response") Log.e(TAG, "HttpException, unexpected response")
Toast.makeText(context,R.string.server_error, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated return@launchWhenCreated
} }
var videosNameArray: Array<CharSequence> = arrayOf() var videosNameArray: Array<CharSequence> = arrayOf()
@ -255,7 +270,19 @@ class PlayerFragment : Fragment() {
) )
} }
val cronetEngine: CronetEngine = CronetEngine.Builder(context)
.build()
val cronetDataSourceFactory: CronetDataSource.Factory =
CronetDataSource.Factory(cronetEngine, Executors.newCachedThreadPool())
val dataSourceFactory = DefaultDataSource.Factory(
requireContext(),
cronetDataSourceFactory
)
exoPlayer = ExoPlayer.Builder(view.context) exoPlayer = ExoPlayer.Builder(view.context)
.setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory))
.setSeekBackIncrementMs(5000) .setSeekBackIncrementMs(5000)
.setSeekForwardIncrementMs(5000) .setSeekForwardIncrementMs(5000)
.build() .build()
@ -265,14 +292,15 @@ class PlayerFragment : Fragment() {
// exoPlayerView.controllerShowTimeoutMs = 1500 // exoPlayerView.controllerShowTimeoutMs = 1500
exoPlayerView.controllerHideOnTouch = true exoPlayerView.controllerHideOnTouch = true
exoPlayerView.player = exoPlayer exoPlayerView.player = exoPlayer
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext())
val defres = sharedPreferences.getString("default_res", "")!! val defres = sharedPreferences.getString("default_res", "")!!
when { when {
defres!="" -> { defres != "" -> {
var foundRes = false var foundRes = false
run lit@ { run lit@{
response.videoStreams!!.forEachIndexed { index, pipedStream -> response.videoStreams!!.forEachIndexed { index, pipedStream ->
if (pipedStream.quality!!.contains(defres)){ if (pipedStream.quality!!.contains(defres)) {
foundRes = true foundRes = true
val dataSourceFactory: DataSource.Factory = val dataSourceFactory: DataSource.Factory =
DefaultHttpDataSource.Factory() DefaultHttpDataSource.Factory()
@ -280,24 +308,35 @@ class PlayerFragment : Fragment() {
.setUri(response.videoStreams[index].url) .setUri(response.videoStreams[index].url)
.setSubtitleConfigurations(subtitle) .setSubtitleConfigurations(subtitle)
.build() .build()
val videoSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) val videoSource: MediaSource =
.createMediaSource(videoItem) DefaultMediaSourceFactory(dataSourceFactory)
var audioSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) .createMediaSource(videoItem)
.createMediaSource(fromUri(response.audioStreams!![0].url!!)) var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[index].quality == "720p" || response.videoStreams[index].quality == "1080p" || response.videoStreams[index].quality == "480p") { if (response.videoStreams[index].quality == "720p" || response.videoStreams[index].quality == "1080p" || response.videoStreams[index].quality == "480p") {
audioSource = ProgressiveMediaSource.Factory(dataSourceFactory) audioSource =
.createMediaSource(fromUri(response.audioStreams!![getMostBitRate(response.audioStreams)].url!!)) ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(
fromUri(
response.audioStreams!![getMostBitRate(
response.audioStreams
)].url!!
)
)
} }
val mergeSource: MediaSource = MergingMediaSource(videoSource, audioSource) val mergeSource: MediaSource =
MergingMediaSource(videoSource, audioSource)
exoPlayer.setMediaSource(mergeSource) exoPlayer.setMediaSource(mergeSource)
view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[index + 1] view.findViewById<TextView>(R.id.quality_text).text =
videosNameArray[index + 1]
return@lit return@lit
}else if (index+1 == response.videoStreams.size){ } else if (index + 1 == response.videoStreams.size) {
val mediaItem: MediaItem = MediaItem.Builder() val mediaItem: MediaItem = MediaItem.Builder()
.setUri(response.hls) .setUri(response.hls)
.setSubtitleConfigurations(subtitle) .setSubtitleConfigurations(subtitle)
.build() .build()
exoPlayer.setMediaItem(mediaItem) exoPlayer.setMediaItem(mediaItem)
} }
} }
} }
@ -316,15 +355,24 @@ class PlayerFragment : Fragment() {
.setUri(response.videoStreams[0].url) .setUri(response.videoStreams[0].url)
.setSubtitleConfigurations(subtitle) .setSubtitleConfigurations(subtitle)
.build() .build()
val videoSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) val videoSource: MediaSource =
.createMediaSource(videoItem) DefaultMediaSourceFactory(dataSourceFactory)
var audioSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) .createMediaSource(videoItem)
.createMediaSource(fromUri(response.audioStreams!![0].url!!)) var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[0].quality == "720p" || response.videoStreams[0].quality == "1080p" || response.videoStreams[0].quality == "480p") { if (response.videoStreams[0].quality == "720p" || response.videoStreams[0].quality == "1080p" || response.videoStreams[0].quality == "480p") {
audioSource = ProgressiveMediaSource.Factory(dataSourceFactory) audioSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![getMostBitRate(response.audioStreams)].url!!)) .createMediaSource(
fromUri(
response.audioStreams!![getMostBitRate(
response.audioStreams
)].url!!
)
)
} }
val mergeSource: MediaSource = MergingMediaSource(videoSource, audioSource) val mergeSource: MediaSource =
MergingMediaSource(videoSource, audioSource)
exoPlayer.setMediaSource(mergeSource) exoPlayer.setMediaSource(mergeSource)
view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[1] view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[1]
} }
@ -371,18 +419,29 @@ class PlayerFragment : Fragment() {
.setUri(response.videoStreams[which - 1].url) .setUri(response.videoStreams[which - 1].url)
.setSubtitleConfigurations(subtitle) .setSubtitleConfigurations(subtitle)
.build() .build()
val videoSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) val videoSource: MediaSource =
.createMediaSource(videoItem) DefaultMediaSourceFactory(dataSourceFactory)
var audioSource: MediaSource = DefaultMediaSourceFactory(dataSourceFactory) .createMediaSource(videoItem)
.createMediaSource(fromUri(response.audioStreams!![0].url!!)) var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[which - 1].quality == "720p" || response.videoStreams[which - 1].quality == "1080p" || response.videoStreams[which - 1].quality == "480p") { if (response.videoStreams[which - 1].quality == "720p" || response.videoStreams[which - 1].quality == "1080p" || response.videoStreams[which - 1].quality == "480p") {
audioSource = ProgressiveMediaSource.Factory(dataSourceFactory) audioSource =
.createMediaSource(fromUri(response.audioStreams!![getMostBitRate(response.audioStreams)].url!!)) ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(
fromUri(
response.audioStreams!![getMostBitRate(
response.audioStreams
)].url!!
)
)
} }
val mergeSource: MediaSource = MergingMediaSource(videoSource, audioSource) val mergeSource: MediaSource =
MergingMediaSource(videoSource, audioSource)
exoPlayer.setMediaSource(mergeSource) exoPlayer.setMediaSource(mergeSource)
} }
view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[which] view.findViewById<TextView>(R.id.quality_text).text =
videosNameArray[which]
} }
) )
val dialog: AlertDialog? = builder?.create() val dialog: AlertDialog? = builder?.create()
@ -390,34 +449,42 @@ class PlayerFragment : Fragment() {
} }
// Listener for play and pause icon change // Listener for play and pause icon change
exoPlayer!!.addListener(object : com.google.android.exoplayer2.Player.Listener { exoPlayer!!.addListener(object : com.google.android.exoplayer2.Player.Listener {
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { override fun onPlayerStateChanged(
playWhenReady: Boolean,
playbackState: Int
) {
exoPlayerView.keepScreenOn = !( exoPlayerView.keepScreenOn = !(
playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED || playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED ||
!playWhenReady !playWhenReady
) )
if (playWhenReady && playbackState == Player.STATE_READY) { if (playWhenReady && playbackState == Player.STATE_READY) {
// media actually playing // media actually playing
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_pause) view.findViewById<ImageView>(R.id.play_imageView)
.setImageResource(R.drawable.ic_pause)
} else if (playWhenReady) { } else if (playWhenReady) {
// might be idle (plays after prepare()), // might be idle (plays after prepare()),
// buffering (plays when data available) // buffering (plays when data available)
// or ended (plays when seek away from end) // or ended (plays when seek away from end)
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_play) view.findViewById<ImageView>(R.id.play_imageView)
.setImageResource(R.drawable.ic_play)
} else { } else {
// player paused in any state // player paused in any state
view.findViewById<ImageView>(R.id.play_imageView).setImageResource(R.drawable.ic_play) view.findViewById<ImageView>(R.id.play_imageView)
.setImageResource(R.drawable.ic_play)
} }
} }
}) })
relatedRecView.adapter = TrendingAdapter(response.relatedStreams!!) relatedRecView.adapter = TrendingAdapter(response.relatedStreams!!)
view.findViewById<TextView>(R.id.player_description).text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { view.findViewById<TextView>(R.id.player_description).text =
Html.fromHtml(response.description, Html.FROM_HTML_MODE_COMPACT) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
} else { Html.fromHtml(response.description, Html.FROM_HTML_MODE_COMPACT)
Html.fromHtml(response.description) } else {
} Html.fromHtml(response.description)
view.findViewById<TextView>(R.id.player_views_info).text = response.views.formatShort() + " views • " + response.uploadDate }
view.findViewById<TextView>(R.id.player_views_info).text =
response.views.formatShort() + " views • " + response.uploadDate
view.findViewById<TextView>(R.id.textLike).text = response.likes.formatShort() view.findViewById<TextView>(R.id.textLike).text = response.likes.formatShort()
val channelImage = view.findViewById<ImageView>(R.id.player_channelImage) val channelImage = view.findViewById<ImageView>(R.id.player_channelImage)
Picasso.get().load(response.uploaderAvatar).into(channelImage) Picasso.get().load(response.uploaderAvatar).into(channelImage)
@ -438,11 +505,15 @@ class PlayerFragment : Fragment() {
} }
// share button // share button
view.findViewById<RelativeLayout>(R.id.relPlayer_share).setOnClickListener { view.findViewById<RelativeLayout>(R.id.relPlayer_share).setOnClickListener {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext())
val intent = Intent() val intent = Intent()
intent.action = Intent.ACTION_SEND intent.action = Intent.ACTION_SEND
var url = "https://piped.kavin.rocks/watch?v=$videoId" var url = "https://piped.kavin.rocks/watch?v=$videoId"
val instance = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks")!! val instance = sharedPreferences.getString(
"instance",
"https://pipedapi.kavin.rocks"
)!!
if (instance != "https://pipedapi.kavin.rocks") if (instance != "https://pipedapi.kavin.rocks")
url += "&instance=${URLEncoder.encode(instance, "UTF-8")}" url += "&instance=${URLEncoder.encode(instance, "UTF-8")}"
intent.putExtra(Intent.EXTRA_TEXT, url) intent.putExtra(Intent.EXTRA_TEXT, url)
@ -450,7 +521,7 @@ class PlayerFragment : Fragment() {
startActivity(Intent.createChooser(intent, "Share Url To:")) startActivity(Intent.createChooser(intent, "Share Url To:"))
} }
// check if livestream // check if livestream
if (response.duration!!> 0) { if (response.duration!! > 0) {
// download clicked // download clicked
relDownloadVideo.setOnClickListener { relDownloadVideo.setOnClickListener {
if (!IS_DOWNLOAD_RUNNING) { if (!IS_DOWNLOAD_RUNNING) {
@ -473,9 +544,9 @@ class PlayerFragment : Fragment() {
requireContext(), requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission( ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
requireContext(), requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED ) != PackageManager.PERMISSION_GRANTED
) { ) {
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(
mainActivity, mainActivity,
@ -540,7 +611,7 @@ class PlayerFragment : Fragment() {
Toast.makeText(context, R.string.vlcerror, Toast.LENGTH_SHORT) Toast.makeText(context, R.string.vlcerror, Toast.LENGTH_SHORT)
.show() .show()
} }
} }
} }
} }
} }
@ -554,7 +625,10 @@ class PlayerFragment : Fragment() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val response = try { val response = try {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
RetrofitInstance.api.isSubscribed(channel_id, sharedPref?.getString("token", "")!!) RetrofitInstance.api.isSubscribed(
channel_id,
sharedPref?.getString("token", "")!!
)
} catch (e: IOException) { } catch (e: IOException) {
println(e) println(e)
Log.e(TAG, "IOException, you might not have internet connection") Log.e(TAG, "IOException, you might not have internet connection")
@ -594,7 +668,7 @@ class PlayerFragment : Fragment() {
button.text = getString(R.string.unsubscribe) button.text = getString(R.string.unsubscribe)
button.setTextColor(colorPrimary.data) button.setTextColor(colorPrimary.data)
} }
} }
} }
} }
} }
@ -607,7 +681,10 @@ class PlayerFragment : Fragment() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val response = try { val response = try {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
RetrofitInstance.api.subscribe(sharedPref?.getString("token", "")!!, Subscribe(channel_id)) RetrofitInstance.api.subscribe(
sharedPref?.getString("token", "")!!,
Subscribe(channel_id)
)
} catch (e: IOException) { } catch (e: IOException) {
println(e) println(e)
Log.e(TAG, "IOException, you might not have internet connection") Log.e(TAG, "IOException, you might not have internet connection")
@ -621,12 +698,16 @@ class PlayerFragment : Fragment() {
} }
run() run()
} }
private fun unsubscribe(channel_id: String) { private fun unsubscribe(channel_id: String) {
fun run() { fun run() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val response = try { val response = try {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
RetrofitInstance.api.unsubscribe(sharedPref?.getString("token", "")!!, Subscribe(channel_id)) RetrofitInstance.api.unsubscribe(
sharedPref?.getString("token", "")!!,
Subscribe(channel_id)
)
} catch (e: IOException) { } catch (e: IOException) {
println(e) println(e)
Log.e(TAG, "IOException, you might not have internet connection") Log.e(TAG, "IOException, you might not have internet connection")
@ -652,7 +733,7 @@ class PlayerFragment : Fragment() {
var index = 0 var index = 0
for ((i, audio) in audios.withIndex()) { for ((i, audio) in audios.withIndex()) {
val q = audio.quality!!.replace(" kbps", "").toInt() val q = audio.quality!!.replace(" kbps", "").toInt()
if (q> bitrate) { if (q > bitrate) {
bitrate = q bitrate = q
index = i index = i
} }

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:src="@drawable/ic_libretube_foreground"
android:layout_width="match_parent"
android:layout_height="64dp"
android:scaleType="center"
android:background="#CD5757"
android:contentDescription="@string/app_name" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false"
android:layout_marginTop="16dp"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"
android:layout_marginBottom="4dp"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/playlistName"
android:inputType="text"
android:padding="12dp" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/create_playlist_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/createPlaylist"
android:padding="8dp"
android:layout_margin="8dp"/>
</LinearLayout>
</LinearLayout>

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -46,6 +48,34 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/outlinedTextField"
style="@style/Widget.Material3.CardView.Filled"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="5dp"
>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:background="@android:color/transparent">
<EditText
android:id="@+id/playlists_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:layout_margin="8dp"
android:background="@android:color/transparent"
android:hint="@string/playlistName"/>
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.card.MaterialCardView>
<Button <Button
android:id="@+id/create_playlist" android:id="@+id/create_playlist"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -45,4 +45,5 @@
<string name="areYouSure">Are you sure you want to delete this playlist?</string> <string name="areYouSure">Are you sure you want to delete this playlist?</string>
<string name="createPlaylist">Create Playlist</string> <string name="createPlaylist">Create Playlist</string>
<string name="playlistCreated">Playlist created!</string> <string name="playlistCreated">Playlist created!</string>
<string name="playlistName">Playlist Name</string>
</resources> </resources>

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.1' classpath 'com.android.tools.build:gradle:7.1.3'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong