mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 07:50:31 +05:30
Fix all linting errors.
This commit is contained in:
parent
940a3b20e7
commit
057cf3f02f
@ -2,7 +2,7 @@ package com.github.libretube
|
|||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@ -6,15 +6,19 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.Spinner
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.github.libretube.obj.PlaylistId
|
import com.github.libretube.obj.PlaylistId
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import retrofit2.HttpException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class AddtoPlaylistDialog : DialogFragment() {
|
class AddtoPlaylistDialog : DialogFragment() {
|
||||||
private val TAG = "AddToPlaylistDialog"
|
private val TAG = "AddToPlaylistDialog"
|
||||||
@ -49,6 +53,7 @@ class AddtoPlaylistDialog : DialogFragment() {
|
|||||||
builder.create()
|
builder.create()
|
||||||
} ?: throw IllegalStateException("Activity cannot be null")
|
} ?: throw IllegalStateException("Activity cannot be null")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchPlaylists() {
|
private fun fetchPlaylists() {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -69,8 +74,11 @@ class AddtoPlaylistDialog : DialogFragment() {
|
|||||||
for (playlist in response) {
|
for (playlist in response) {
|
||||||
names.add(playlist.name!!)
|
names.add(playlist.name!!)
|
||||||
}
|
}
|
||||||
val arrayAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
|
val arrayAdapter =
|
||||||
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
|
||||||
|
arrayAdapter.setDropDownViewResource(
|
||||||
|
android.R.layout.simple_spinner_dropdown_item
|
||||||
|
)
|
||||||
spinner.adapter = arrayAdapter
|
spinner.adapter = arrayAdapter
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
button.setOnClickListener {
|
button.setOnClickListener {
|
||||||
@ -83,6 +91,7 @@ class AddtoPlaylistDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addToPlaylist(playlistId: String) {
|
private fun addToPlaylist(playlistId: String) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -108,6 +117,7 @@ class AddtoPlaylistDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||||
this ?: return
|
this ?: return
|
||||||
if (!isAdded) return // Fragment not attached to an Activity
|
if (!isAdded) return // Fragment not attached to an Activity
|
||||||
|
@ -3,7 +3,6 @@ package com.github.libretube
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils.substring
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -94,7 +93,10 @@ class ChannelFragment : 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")
|
||||||
@ -131,7 +133,10 @@ class ChannelFragment : 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")
|
||||||
@ -145,12 +150,16 @@ class ChannelFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsubscribe() {
|
private fun unsubscribe() {
|
||||||
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")
|
||||||
@ -186,12 +195,19 @@ class ChannelFragment : Fragment() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
view.findViewById<ScrollView>(R.id.channel_scrollView).visibility = View.VISIBLE
|
view.findViewById<ScrollView>(R.id.channel_scrollView).visibility = View.VISIBLE
|
||||||
val channelName = view.findViewById<TextView>(R.id.channel_name)
|
val channelName = view.findViewById<TextView>(R.id.channel_name)
|
||||||
channelName.text = if (response.name?.length!! > 18) response.name.toString().substring(0, 16) + "..." else response.name
|
channelName.text = if (response.name?.length!! > 18) response.name.toString()
|
||||||
|
.substring(0, 16) + "..." else response.name
|
||||||
val channelVerified = view.findViewById<ImageView>(R.id.channel_verified)
|
val channelVerified = view.findViewById<ImageView>(R.id.channel_verified)
|
||||||
if (response.verified) channelVerified.visibility = View.VISIBLE
|
if (response.verified) channelVerified.visibility = View.VISIBLE
|
||||||
view.findViewById<TextView>(R.id.channel_subs).text = resources.getString(R.string.subscribers, response.subscriberCount.formatShort())
|
view.findViewById<TextView>(R.id.channel_subs).text = resources.getString(
|
||||||
|
R.string.subscribers,
|
||||||
|
response.subscriberCount.formatShort()
|
||||||
|
)
|
||||||
val channelDescription = view.findViewById<TextView>(R.id.channel_description)
|
val channelDescription = view.findViewById<TextView>(R.id.channel_description)
|
||||||
if (response.description?.trim() == "") channelDescription.visibility = View.GONE else channelDescription.text = response.description?.trim()
|
if (response.description?.trim() == "")
|
||||||
|
channelDescription.visibility = View.GONE
|
||||||
|
else
|
||||||
|
channelDescription.text = response.description?.trim()
|
||||||
val bannerImage = view.findViewById<ImageView>(R.id.channel_banner)
|
val bannerImage = view.findViewById<ImageView>(R.id.channel_banner)
|
||||||
val channelImage = view.findViewById<ImageView>(R.id.channel_image)
|
val channelImage = view.findViewById<ImageView>(R.id.channel_image)
|
||||||
Picasso.get().load(response.bannerUrl).into(bannerImage)
|
Picasso.get().load(response.bannerUrl).into(bannerImage)
|
||||||
@ -203,6 +219,7 @@ class ChannelFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchNextPage() {
|
private fun fetchNextPage() {
|
||||||
fun run() {
|
fun run() {
|
||||||
|
|
||||||
@ -227,6 +244,7 @@ class ChannelFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||||
this ?: return
|
this ?: return
|
||||||
if (!isAdded) return // Fragment not attached to an Activity
|
if (!isAdded) return // Fragment not attached to an Activity
|
||||||
|
@ -12,6 +12,7 @@ import androidx.core.os.bundleOf
|
|||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.setFragmentResult
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
||||||
class CreatePlaylistDialog : DialogFragment() {
|
class CreatePlaylistDialog : DialogFragment() {
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -35,7 +36,7 @@ class CreatePlaylistDialog : DialogFragment() {
|
|||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
val playlistName = rootView.findViewById<com.google.android.material.textfield.TextInputEditText>(R.id.playlist_name)
|
val playlistName = rootView.findViewById<TextInputEditText>(R.id.playlist_name)
|
||||||
val createPlaylistBtn = rootView.findViewById<Button>(R.id.create_new_playlist)
|
val createPlaylistBtn = rootView.findViewById<Button>(R.id.create_new_playlist)
|
||||||
createPlaylistBtn.setOnClickListener {
|
createPlaylistBtn.setOnClickListener {
|
||||||
var listName = playlistName.text.toString()
|
var listName = playlistName.text.toString()
|
||||||
|
@ -6,7 +6,13 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import android.widget.RadioGroup
|
||||||
|
import android.widget.Spinner
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@ -35,7 +41,11 @@ class DownloadDialog : DialogFragment() {
|
|||||||
val inflater = requireActivity().layoutInflater
|
val inflater = requireActivity().layoutInflater
|
||||||
var view: View = inflater.inflate(R.layout.dialog_download, null)
|
var view: View = inflater.inflate(R.layout.dialog_download, null)
|
||||||
val videoSpinner = view.findViewById<Spinner>(R.id.video_spinner)
|
val videoSpinner = view.findViewById<Spinner>(R.id.video_spinner)
|
||||||
val videoArrayAdapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_spinner_item, vidName)
|
val videoArrayAdapter = ArrayAdapter<String>(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
vidName
|
||||||
|
)
|
||||||
videoArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
videoArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
videoSpinner.adapter = videoArrayAdapter
|
videoSpinner.adapter = videoArrayAdapter
|
||||||
videoSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
videoSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
@ -48,10 +58,15 @@ class DownloadDialog : DialogFragment() {
|
|||||||
selectedVideo = position
|
selectedVideo = position
|
||||||
Log.d(TAG, selectedVideo.toString())
|
Log.d(TAG, selectedVideo.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||||
}
|
}
|
||||||
val audioSpinner = view.findViewById<Spinner>(R.id.audio_spinner)
|
val audioSpinner = view.findViewById<Spinner>(R.id.audio_spinner)
|
||||||
val audioArrayAdapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_spinner_item, audioName)
|
val audioArrayAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
audioName
|
||||||
|
)
|
||||||
audioArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
audioArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
audioSpinner.adapter = audioArrayAdapter
|
audioSpinner.adapter = audioArrayAdapter
|
||||||
audioSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
audioSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
@ -64,6 +79,7 @@ class DownloadDialog : DialogFragment() {
|
|||||||
selectedAudio = position
|
selectedAudio = position
|
||||||
Log.d(TAG, selectedAudio.toString())
|
Log.d(TAG, selectedAudio.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||||
}
|
}
|
||||||
val radioGroup = view.findViewById<RadioGroup>(R.id.radioGp)
|
val radioGroup = view.findViewById<RadioGroup>(R.id.radioGp)
|
||||||
@ -97,6 +113,7 @@ class DownloadDialog : DialogFragment() {
|
|||||||
builder.create()
|
builder.create()
|
||||||
} ?: throw IllegalStateException("Activity cannot be null")
|
} ?: throw IllegalStateException("Activity cannot be null")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
vidName.clear()
|
vidName.clear()
|
||||||
vidUrl.clear()
|
vidUrl.clear()
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import android.app.*
|
import android.app.DownloadManager
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.Service
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@ -9,6 +14,7 @@ import android.graphics.Color
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.os.Environment.DIRECTORY_DOWNLOADS
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
@ -17,6 +23,7 @@ import com.arthenica.ffmpegkit.FFmpegKit
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
var IS_DOWNLOAD_RUNNING = false
|
var IS_DOWNLOAD_RUNNING = false
|
||||||
|
|
||||||
class DownloadService : Service() {
|
class DownloadService : Service() {
|
||||||
val TAG = "DownloadService"
|
val TAG = "DownloadService"
|
||||||
private var downloadId: Long = -1
|
private var downloadId: Long = -1
|
||||||
@ -25,6 +32,7 @@ class DownloadService : Service() {
|
|||||||
private lateinit var audioUrl: String
|
private lateinit var audioUrl: String
|
||||||
private lateinit var extension: String
|
private lateinit var extension: String
|
||||||
private var duration: Int = 0
|
private var duration: Int = 0
|
||||||
|
|
||||||
// private lateinit var command: String
|
// private lateinit var command: String
|
||||||
private lateinit var audioDir: File
|
private lateinit var audioDir: File
|
||||||
private lateinit var videoDir: File
|
private lateinit var videoDir: File
|
||||||
@ -81,6 +89,7 @@ class DownloadService : Service() {
|
|||||||
|
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
@ -101,7 +110,10 @@ class DownloadService : Service() {
|
|||||||
videoDir = File(f, "$videoId-video")
|
videoDir = File(f, "$videoId-video")
|
||||||
try {
|
try {
|
||||||
Log.e(TAG, "Directory make")
|
Log.e(TAG, "Directory make")
|
||||||
registerReceiver(onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
registerReceiver(
|
||||||
|
onDownloadComplete,
|
||||||
|
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
|
||||||
|
)
|
||||||
val request: DownloadManager.Request =
|
val request: DownloadManager.Request =
|
||||||
DownloadManager.Request(Uri.parse(videoUrl))
|
DownloadManager.Request(Uri.parse(videoUrl))
|
||||||
.setTitle("Video") // Title of the Download Notification
|
.setTitle("Video") // Title of the Download Notification
|
||||||
@ -113,7 +125,9 @@ class DownloadService : Service() {
|
|||||||
val downloadManager: DownloadManager =
|
val downloadManager: DownloadManager =
|
||||||
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
|
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
|
||||||
downloadId = downloadManager.enqueue(request)
|
downloadId = downloadManager.enqueue(request)
|
||||||
if (audioUrl == "") { downloadId = 0L }
|
if (audioUrl == "") {
|
||||||
|
downloadId = 0L
|
||||||
|
}
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
Log.e(TAG, "download error $e")
|
Log.e(TAG, "download error $e")
|
||||||
try {
|
try {
|
||||||
@ -155,9 +169,12 @@ class DownloadService : Service() {
|
|||||||
val downloadManager: DownloadManager =
|
val downloadManager: DownloadManager =
|
||||||
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
|
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
|
||||||
downloadManager.enqueue(request)
|
downloadManager.enqueue(request)
|
||||||
} catch (e: Exception) {}
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
} else if (downloadId == 0L) {
|
} else if (downloadId == 0L) {
|
||||||
val libreTube = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LibreTube")
|
val libreTube = File(
|
||||||
|
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "LibreTube"
|
||||||
|
)
|
||||||
if (!libreTube.exists()) {
|
if (!libreTube.exists()) {
|
||||||
libreTube.mkdirs()
|
libreTube.mkdirs()
|
||||||
Log.e(TAG, "libreTube Directory make")
|
Log.e(TAG, "libreTube Directory make")
|
||||||
@ -191,7 +208,8 @@ class DownloadService : Service() {
|
|||||||
session.failStackTrace
|
session.failStackTrace
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val path = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
|
val path =
|
||||||
|
applicationContext.getExternalFilesDir(DIRECTORY_DOWNLOADS)
|
||||||
val folder_main = ".tmp"
|
val folder_main = ".tmp"
|
||||||
val f = File(path, folder_main)
|
val f = File(path, folder_main)
|
||||||
f.deleteRecursively()
|
f.deleteRecursively()
|
||||||
@ -243,10 +261,12 @@ class DownloadService : Service() {
|
|||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
try {
|
try {
|
||||||
unregisterReceiver(onDownloadComplete)
|
unregisterReceiver(onDownloadComplete)
|
||||||
} catch (e: Exception) {}
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
IS_DOWNLOAD_RUNNING = false
|
IS_DOWNLOAD_RUNNING = false
|
||||||
Log.d(TAG, "dl finished!")
|
Log.d(TAG, "dl finished!")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
@ -15,7 +15,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.github.libretube.adapters.TrendingAdapter
|
import com.github.libretube.adapters.TrendingAdapter
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import okhttp3.*
|
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class Home : Fragment() {
|
class Home : Fragment() {
|
||||||
@ -42,7 +41,10 @@ class Home : Fragment() {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
|
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
val grid = sharedPreferences.getString("grid", resources.getInteger(R.integer.grid_items).toString())!!
|
val grid = sharedPreferences.getString(
|
||||||
|
"grid",
|
||||||
|
resources.getInteger(R.integer.grid_items).toString()
|
||||||
|
)!!
|
||||||
recyclerView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
recyclerView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
||||||
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
|
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
|
||||||
fetchJson(progressbar, recyclerView)
|
fetchJson(progressbar, recyclerView)
|
||||||
@ -58,7 +60,8 @@ class Home : Fragment() {
|
|||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val response = try {
|
val response = try {
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
RetrofitInstance.api.getTrending(sharedPreferences.getString("region", "US")!!)
|
RetrofitInstance.api.getTrending(sharedPreferences.getString("region", "US")!!)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
@ -80,6 +83,7 @@ class Home : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||||
this ?: return
|
this ?: return
|
||||||
if (!isAdded) return // Fragment not attached to an Activity
|
if (!isAdded) return // Fragment not attached to an Activity
|
||||||
|
@ -52,8 +52,8 @@ class Library : Fragment() {
|
|||||||
view.findViewById<ImageView>(R.id.boogh2).visibility = View.GONE
|
view.findViewById<ImageView>(R.id.boogh2).visibility = View.GONE
|
||||||
view.findViewById<TextView>(R.id.textLike2).visibility = View.GONE
|
view.findViewById<TextView>(R.id.textLike2).visibility = View.GONE
|
||||||
fetchPlaylists(view)
|
fetchPlaylists(view)
|
||||||
refreshLayout?.isEnabled = true
|
refreshLayout.isEnabled = true
|
||||||
refreshLayout?.setOnRefreshListener {
|
refreshLayout.setOnRefreshListener {
|
||||||
Log.d(TAG, "hmm")
|
Log.d(TAG, "hmm")
|
||||||
fetchPlaylists(view)
|
fetchPlaylists(view)
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ class Library : Fragment() {
|
|||||||
createPlaylist("$playlistName", view)
|
createPlaylist("$playlistName", view)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
refreshLayout?.isEnabled = false
|
refreshLayout.isEnabled = false
|
||||||
view.findViewById<Button>(R.id.create_playlist).visibility = View.GONE
|
view.findViewById<Button>(R.id.create_playlist).visibility = View.GONE
|
||||||
with(view.findViewById<ImageView>(R.id.boogh2)) {
|
with(view.findViewById<ImageView>(R.id.boogh2)) {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
@ -81,7 +81,7 @@ class Library : Fragment() {
|
|||||||
|
|
||||||
private fun fetchPlaylists(view: View) {
|
private fun fetchPlaylists(view: View) {
|
||||||
fun run() {
|
fun run() {
|
||||||
refreshLayout?.isRefreshing = true
|
refreshLayout.isRefreshing = true
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val response = try {
|
val response = try {
|
||||||
RetrofitInstance.api.playlists(token)
|
RetrofitInstance.api.playlists(token)
|
||||||
@ -95,7 +95,7 @@ class Library : Fragment() {
|
|||||||
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
|
||||||
} finally {
|
} finally {
|
||||||
refreshLayout?.isRefreshing = false
|
refreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
if (response.isNotEmpty()) {
|
if (response.isNotEmpty()) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
@ -106,7 +106,10 @@ class Library : Fragment() {
|
|||||||
visibility = View.GONE
|
visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val playlistsAdapter = PlaylistsAdapter(response.toMutableList(), requireActivity())
|
val playlistsAdapter = PlaylistsAdapter(
|
||||||
|
response.toMutableList(),
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
playlistRecyclerView.adapter = playlistsAdapter
|
playlistRecyclerView.adapter = playlistsAdapter
|
||||||
} else {
|
} else {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
@ -124,6 +127,7 @@ class Library : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPlaylist(name: String, view: View) {
|
private fun createPlaylist(name: String, view: View) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
|
@ -15,8 +15,8 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.github.libretube.obj.Login
|
import com.github.libretube.obj.Login
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import retrofit2.HttpException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class LoginDialog : DialogFragment() {
|
class LoginDialog : DialogFragment() {
|
||||||
private val TAG = "LoginDialog"
|
private val TAG = "LoginDialog"
|
||||||
@ -35,7 +35,8 @@ class LoginDialog : DialogFragment() {
|
|||||||
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 = inflater.inflate(R.layout.dialog_logout, null)
|
view = inflater.inflate(R.layout.dialog_logout, null)
|
||||||
view.findViewById<TextView>(R.id.user).text = view.findViewById<TextView>(R.id.user).text.toString() + " (" + user + ")"
|
view.findViewById<TextView>(R.id.user).text =
|
||||||
|
view.findViewById<TextView>(R.id.user).text.toString() + " (" + user + ")"
|
||||||
view.findViewById<Button>(R.id.logout).setOnClickListener {
|
view.findViewById<Button>(R.id.logout).setOnClickListener {
|
||||||
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show()
|
||||||
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
||||||
@ -76,11 +77,11 @@ class LoginDialog : DialogFragment() {
|
|||||||
)
|
)
|
||||||
view.findViewById<TextView>(R.id.title).text = appName
|
view.findViewById<TextView>(R.id.title).text = appName
|
||||||
|
|
||||||
|
|
||||||
builder.setView(view)
|
builder.setView(view)
|
||||||
builder.create()
|
builder.create()
|
||||||
} ?: throw IllegalStateException("Activity cannot be null")
|
} ?: throw IllegalStateException("Activity cannot be null")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun login(login: Login) {
|
private fun login(login: Login) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -108,7 +109,8 @@ class LoginDialog : DialogFragment() {
|
|||||||
putString("token", response.token)
|
putString("token", response.token)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
val sharedPref2 =
|
||||||
|
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
||||||
with(sharedPref2!!.edit()) {
|
with(sharedPref2!!.edit()) {
|
||||||
putString("username", login.username)
|
putString("username", login.username)
|
||||||
apply()
|
apply()
|
||||||
@ -119,6 +121,7 @@ class LoginDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(login: Login) {
|
private fun register(login: Login) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -146,7 +149,8 @@ class LoginDialog : DialogFragment() {
|
|||||||
putString("token", response.token)
|
putString("token", response.token)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
val sharedPref2 =
|
||||||
|
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
||||||
with(sharedPref2!!.edit()) {
|
with(sharedPref2!!.edit()) {
|
||||||
putString("username", login.username)
|
putString("username", login.username)
|
||||||
apply()
|
apply()
|
||||||
|
@ -12,7 +12,10 @@ import android.os.Bundle
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.*
|
import android.view.View
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.WindowInsetsController
|
||||||
|
import android.view.WindowManager
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
@ -40,25 +43,33 @@ class MainActivity : AppCompatActivity() {
|
|||||||
DynamicColors.applyToActivityIfAvailable(this)
|
DynamicColors.applyToActivityIfAvailable(this)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
RetrofitInstance.url = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
|
RetrofitInstance.url =
|
||||||
SponsorBlockSettings.sponsorBlockEnabled = sharedPreferences.getBoolean("sponsorblock_enabled_key", false)
|
sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
|
||||||
SponsorBlockSettings.introEnabled = sharedPreferences.getBoolean("intro_category_key", false)
|
SponsorBlockSettings.sponsorBlockEnabled =
|
||||||
SponsorBlockSettings.selfPromoEnabled = sharedPreferences.getBoolean("selfpromo_category_key", false)
|
sharedPreferences.getBoolean("sponsorblock_enabled_key", false)
|
||||||
SponsorBlockSettings.interactionEnabled = sharedPreferences.getBoolean("interaction_category_key", false)
|
SponsorBlockSettings.introEnabled =
|
||||||
SponsorBlockSettings.sponsorsEnabled = sharedPreferences.getBoolean("sponsors_category_key", false)
|
sharedPreferences.getBoolean("intro_category_key", false)
|
||||||
SponsorBlockSettings.outroEnabled = sharedPreferences.getBoolean("outro_category_key", false)
|
SponsorBlockSettings.selfPromoEnabled =
|
||||||
|
sharedPreferences.getBoolean("selfpromo_category_key", false)
|
||||||
|
SponsorBlockSettings.interactionEnabled =
|
||||||
|
sharedPreferences.getBoolean("interaction_category_key", false)
|
||||||
|
SponsorBlockSettings.sponsorsEnabled =
|
||||||
|
sharedPreferences.getBoolean("sponsors_category_key", false)
|
||||||
|
SponsorBlockSettings.outroEnabled =
|
||||||
|
sharedPreferences.getBoolean("outro_category_key", false)
|
||||||
|
|
||||||
updateAccentColor(this)
|
updateAccentColor(this)
|
||||||
updateThemeMode(this)
|
updateThemeMode(this)
|
||||||
updateLanguage(this)
|
updateLanguage(this)
|
||||||
|
|
||||||
val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
val connectivityManager =
|
||||||
|
this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
val networkInfo = connectivityManager.activeNetworkInfo
|
val networkInfo = connectivityManager.activeNetworkInfo
|
||||||
val isConnected = networkInfo != null && networkInfo.isConnected
|
val isConnected = networkInfo != null && networkInfo.isConnected
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
setContentView(R.layout.activity_nointernet)
|
setContentView(R.layout.activity_nointernet)
|
||||||
findViewById<Button>(R.id.retry_button).setOnClickListener() {
|
findViewById<Button>(R.id.retry_button).setOnClickListener {
|
||||||
recreate()
|
recreate()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -137,10 +148,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (data.host != null) {
|
if (data.host != null) {
|
||||||
if (data.path != null) {
|
if (data.path != null) {
|
||||||
// channel
|
// channel
|
||||||
if (data.path!!.contains("/channel/") || data.path!!.contains("/c/") || data.path!!.contains("/user/")) {
|
if (data.path!!.contains("/channel/") ||
|
||||||
|
data.path!!.contains("/c/") ||
|
||||||
|
data.path!!.contains("/user/")
|
||||||
|
) {
|
||||||
var channel = data.path
|
var channel = data.path
|
||||||
channel = channel!!.replace("/c/", "")
|
channel = channel!!.replace("/c/", "")
|
||||||
channel = channel!!.replace("/user/", "")
|
channel = channel.replace("/user/", "")
|
||||||
val bundle = bundleOf("channel_id" to channel)
|
val bundle = bundleOf("channel_id" to channel)
|
||||||
navController.navigate(R.id.channel, bundle)
|
navController.navigate(R.id.channel, bundle)
|
||||||
} else if (data.path!!.contains("/playlist")) {
|
} else if (data.path!!.contains("/playlist")) {
|
||||||
@ -157,11 +171,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
playlist = playlist.replace("list=", "")
|
playlist = playlist.replace("list=", "")
|
||||||
val bundle = bundleOf("playlist_id" to playlist)
|
val bundle = bundleOf("playlist_id" to playlist)
|
||||||
navController.navigate(R.id.playlistFragment, bundle)
|
navController.navigate(R.id.playlistFragment, bundle)
|
||||||
} else if (data.path!!.contains("/shorts/") || data.path!!.contains("/embed/") || data.path!!.contains("/v/")) {
|
} else if (data.path!!.contains("/shorts/") ||
|
||||||
var watch = data.path!!.replace("/shorts/", "").replace("/v/", "").replace("/embed/", "")
|
data.path!!.contains("/embed/") ||
|
||||||
var bundle = Bundle()
|
data.path!!.contains("/v/")
|
||||||
|
) {
|
||||||
|
val watch = data.path!!
|
||||||
|
.replace("/shorts/", "")
|
||||||
|
.replace("/v/", "")
|
||||||
|
.replace("/embed/", "")
|
||||||
|
val bundle = Bundle()
|
||||||
bundle.putString("videoId", watch)
|
bundle.putString("videoId", watch)
|
||||||
var frag = PlayerFragment()
|
val frag = PlayerFragment()
|
||||||
frag.arguments = bundle
|
frag.arguments = bundle
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.remove(PlayerFragment())
|
.remove(PlayerFragment())
|
||||||
@ -241,7 +261,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
isFullScreen = false
|
isFullScreen = false
|
||||||
} else {
|
} else {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
if (navController.currentBackStackEntry == null && (parent as View).id != R.id.settings) {
|
if (navController.currentBackStackEntry == null &&
|
||||||
|
(parent as View).id != R.id.settings
|
||||||
|
) {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,6 +272,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
moveTaskToBack(true)
|
moveTaskToBack(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
val orientation = newConfig.orientation
|
val orientation = newConfig.orientation
|
||||||
@ -261,6 +284,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setFullscreen()
|
setFullscreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setFullscreen() {
|
private fun setFullscreen() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
window.attributes.layoutInDisplayCutoutMode =
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
@ -285,6 +309,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsetFullscreen() {
|
private fun unsetFullscreen() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
window.attributes.layoutInDisplayCutoutMode =
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
@ -299,7 +324,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_VISIBLE or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
|
window.decorView.systemUiVisibility =
|
||||||
|
(View.SYSTEM_UI_FLAG_VISIBLE or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,6 +336,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Fragment.hideKeyboard() {
|
fun Fragment.hideKeyboard() {
|
||||||
view?.let { activity?.hideKeyboard(it) }
|
view?.let { activity?.hideKeyboard(it) }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,28 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import com.github.libretube.obj.*
|
import com.github.libretube.obj.Channel
|
||||||
import retrofit2.http.*
|
import com.github.libretube.obj.CommentsPage
|
||||||
|
import com.github.libretube.obj.Instances
|
||||||
|
import com.github.libretube.obj.Login
|
||||||
|
import com.github.libretube.obj.Message
|
||||||
|
import com.github.libretube.obj.Playlist
|
||||||
|
import com.github.libretube.obj.PlaylistId
|
||||||
|
import com.github.libretube.obj.Playlists
|
||||||
|
import com.github.libretube.obj.SearchResult
|
||||||
|
import com.github.libretube.obj.Segments
|
||||||
|
import com.github.libretube.obj.StreamItem
|
||||||
|
import com.github.libretube.obj.Streams
|
||||||
|
import com.github.libretube.obj.Subscribe
|
||||||
|
import com.github.libretube.obj.Subscribed
|
||||||
|
import com.github.libretube.obj.Subscription
|
||||||
|
import com.github.libretube.obj.Token
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
import retrofit2.http.Url
|
||||||
|
|
||||||
interface PipedApi {
|
interface PipedApi {
|
||||||
@GET("trending")
|
@GET("trending")
|
||||||
@ -14,7 +35,10 @@ interface PipedApi {
|
|||||||
suspend fun getComments(@Path("videoId") videoId: String): CommentsPage
|
suspend fun getComments(@Path("videoId") videoId: String): CommentsPage
|
||||||
|
|
||||||
@GET("sponsors/{videoId}")
|
@GET("sponsors/{videoId}")
|
||||||
suspend fun getSegments(@Path("videoId") videoId: String, @Query("category") category: String): Segments
|
suspend fun getSegments(
|
||||||
|
@Path("videoId") videoId: String,
|
||||||
|
@Query("category") category: String
|
||||||
|
): Segments
|
||||||
|
|
||||||
@GET("nextpage/comments/{videoId}")
|
@GET("nextpage/comments/{videoId}")
|
||||||
suspend fun getCommentsNextPage(
|
suspend fun getCommentsNextPage(
|
||||||
@ -75,10 +99,16 @@ interface PipedApi {
|
|||||||
suspend fun subscriptions(@Header("Authorization") token: String): List<Subscription>
|
suspend fun subscriptions(@Header("Authorization") token: String): List<Subscription>
|
||||||
|
|
||||||
@POST("subscribe")
|
@POST("subscribe")
|
||||||
suspend fun subscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
|
suspend fun subscribe(
|
||||||
|
@Header("Authorization") token: String,
|
||||||
|
@Body subscribe: Subscribe
|
||||||
|
): Message
|
||||||
|
|
||||||
@POST("unsubscribe")
|
@POST("unsubscribe")
|
||||||
suspend fun unsubscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
|
suspend fun unsubscribe(
|
||||||
|
@Header("Authorization") token: String,
|
||||||
|
@Body subscribe: Subscribe
|
||||||
|
): Message
|
||||||
|
|
||||||
@POST("import")
|
@POST("import")
|
||||||
suspend fun importSubscriptions(
|
suspend fun importSubscriptions(
|
||||||
@ -91,13 +121,22 @@ interface PipedApi {
|
|||||||
suspend fun playlists(@Header("Authorization") token: String): List<Playlists>
|
suspend fun playlists(@Header("Authorization") token: String): List<Playlists>
|
||||||
|
|
||||||
@POST("user/playlists/delete")
|
@POST("user/playlists/delete")
|
||||||
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: Playlists): PlaylistId
|
suspend fun createPlaylist(
|
||||||
|
@Header("Authorization") token: String,
|
||||||
|
@Body name: Playlists
|
||||||
|
): PlaylistId
|
||||||
|
|
||||||
@POST("user/playlists/add")
|
@POST("user/playlists/add")
|
||||||
suspend fun addToPlaylist(@Header("Authorization") token: String, @Body playlistId: PlaylistId): Message
|
suspend fun addToPlaylist(
|
||||||
|
@Header("Authorization") token: String,
|
||||||
|
@Body playlistId: PlaylistId
|
||||||
|
): Message
|
||||||
|
|
||||||
@POST("user/playlists/remove")
|
@POST("user/playlists/remove")
|
||||||
suspend fun removeFromPlaylist(
|
suspend fun removeFromPlaylist(
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.Intent
|
|
||||||
import com.google.android.material.color.DynamicColors
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
|
||||||
class Player : Activity() {
|
class Player : Activity() {
|
||||||
|
|
||||||
|
@ -22,7 +22,14 @@ import android.view.ViewGroup
|
|||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import android.view.animation.RotateAnimation
|
import android.view.animation.RotateAnimation
|
||||||
import android.widget.*
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.ScrollView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
@ -61,12 +68,12 @@ import com.google.android.exoplayer2.util.RepeatModeUtil
|
|||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import org.chromium.net.CronetEngine
|
|
||||||
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 java.util.concurrent.Executors
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import org.chromium.net.CronetEngine
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
var isFullScreen = false
|
var isFullScreen = false
|
||||||
|
|
||||||
@ -207,34 +214,37 @@ class PlayerFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
view.findViewById<RelativeLayout>(R.id.player_title_layout).setOnClickListener {
|
view.findViewById<RelativeLayout>(R.id.player_title_layout).setOnClickListener {
|
||||||
if (playerDescription.isVisible){
|
if (playerDescription.isVisible) {
|
||||||
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
|
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
|
||||||
image.clearAnimation()
|
image.clearAnimation()
|
||||||
playerDescription.visibility = View.GONE
|
playerDescription.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
//toggle button
|
// toggle button
|
||||||
val rotate = RotateAnimation(
|
val rotate = RotateAnimation(
|
||||||
0F,
|
0F,
|
||||||
180F,
|
180F,
|
||||||
Animation.RELATIVE_TO_SELF,
|
Animation.RELATIVE_TO_SELF,
|
||||||
0.5f,
|
0.5f,
|
||||||
Animation.RELATIVE_TO_SELF,
|
Animation.RELATIVE_TO_SELF,
|
||||||
0.5f
|
0.5f
|
||||||
)
|
)
|
||||||
rotate.duration = 100
|
rotate.duration = 100
|
||||||
rotate.interpolator = LinearInterpolator()
|
rotate.interpolator = LinearInterpolator()
|
||||||
rotate.fillAfter = true
|
rotate.fillAfter = true
|
||||||
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
|
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
|
||||||
image.startAnimation(rotate)
|
image.startAnimation(rotate)
|
||||||
playerDescription.visibility = View.VISIBLE
|
playerDescription.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.findViewById<com.google.android.material.card.MaterialCardView>(R.id.comments_toggle).setOnClickListener {
|
view.findViewById<com.google.android.material.card.MaterialCardView>(R.id.comments_toggle)
|
||||||
commentsRecView.visibility = if (commentsRecView.isVisible) View.GONE else View.VISIBLE
|
.setOnClickListener {
|
||||||
relatedRecView.visibility = if (relatedRecView.isVisible) View.GONE else View.VISIBLE
|
commentsRecView.visibility =
|
||||||
if (!commentsLoaded!!) fetchComments()
|
if (commentsRecView.isVisible) View.GONE else View.VISIBLE
|
||||||
}
|
relatedRecView.visibility =
|
||||||
|
if (relatedRecView.isVisible) View.GONE else View.VISIBLE
|
||||||
|
if (!commentsLoaded!!) fetchComments()
|
||||||
|
}
|
||||||
|
|
||||||
// FullScreen button trigger
|
// FullScreen button trigger
|
||||||
view.findViewById<ImageButton>(R.id.fullscreen).setOnClickListener {
|
view.findViewById<ImageButton>(R.id.fullscreen).setOnClickListener {
|
||||||
@ -266,8 +276,9 @@ class PlayerFragment : Fragment() {
|
|||||||
scrollView.viewTreeObserver
|
scrollView.viewTreeObserver
|
||||||
.addOnScrollChangedListener {
|
.addOnScrollChangedListener {
|
||||||
if (scrollView.getChildAt(0).bottom
|
if (scrollView.getChildAt(0).bottom
|
||||||
== (scrollView.height + scrollView.scrollY)
|
== (scrollView.height + scrollView.scrollY) &&
|
||||||
&& nextPage != null) {
|
nextPage != null
|
||||||
|
) {
|
||||||
fetchNextComments()
|
fetchNextComments()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,8 +287,8 @@ class PlayerFragment : Fragment() {
|
|||||||
commentsRecView.layoutManager = LinearLayoutManager(view.context)
|
commentsRecView.layoutManager = LinearLayoutManager(view.context)
|
||||||
|
|
||||||
commentsRecView.setItemViewCacheSize(20)
|
commentsRecView.setItemViewCacheSize(20)
|
||||||
commentsRecView.setDrawingCacheEnabled(true)
|
commentsRecView.isDrawingCacheEnabled = true
|
||||||
commentsRecView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH)
|
commentsRecView.drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
|
||||||
|
|
||||||
relatedRecView = view.findViewById(R.id.player_recView)
|
relatedRecView = view.findViewById(R.id.player_recView)
|
||||||
relatedRecView.layoutManager =
|
relatedRecView.layoutManager =
|
||||||
@ -287,7 +298,8 @@ class PlayerFragment : Fragment() {
|
|||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
try {
|
try {
|
||||||
exoPlayer.release()
|
exoPlayer.release()
|
||||||
}catch (e: Exception){}
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +322,7 @@ class PlayerFragment : Fragment() {
|
|||||||
|
|
||||||
segmentData.segments.forEach { segment: Segment ->
|
segmentData.segments.forEach { segment: Segment ->
|
||||||
val segmentStart = (segment.segment!![0] * 1000.0f).toLong()
|
val segmentStart = (segment.segment!![0] * 1000.0f).toLong()
|
||||||
val segmentEnd = (segment.segment!![1] * 1000.0f).toLong()
|
val segmentEnd = (segment.segment[1] * 1000.0f).toLong()
|
||||||
val currentPosition = exoPlayer.currentPosition
|
val currentPosition = exoPlayer.currentPosition
|
||||||
if (currentPosition in segmentStart until segmentEnd) {
|
if (currentPosition in segmentStart until segmentEnd) {
|
||||||
Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT).show()
|
||||||
@ -383,10 +395,10 @@ class PlayerFragment : Fragment() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
var subtitle = mutableListOf<SubtitleConfiguration>()
|
var subtitle = mutableListOf<SubtitleConfiguration>()
|
||||||
if (response.subtitles!!.isNotEmpty()) {
|
if (response.subtitles!!.isNotEmpty()) {
|
||||||
subtitle?.add(
|
subtitle.add(
|
||||||
SubtitleConfiguration.Builder(response.subtitles!![0].url!!.toUri())
|
SubtitleConfiguration.Builder(response.subtitles[0].url!!.toUri())
|
||||||
.setMimeType(response.subtitles!![0].mimeType!!) // The correct MIME type (required).
|
.setMimeType(response.subtitles[0].mimeType!!) // The correct MIME type (required).
|
||||||
.setLanguage(response.subtitles!![0].code) // The subtitle language (optional).
|
.setLanguage(response.subtitles[0].code) // The subtitle language (optional).
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -426,7 +438,7 @@ class PlayerFragment : Fragment() {
|
|||||||
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 =
|
||||||
@ -440,13 +452,18 @@ class PlayerFragment : Fragment() {
|
|||||||
.createMediaSource(videoItem)
|
.createMediaSource(videoItem)
|
||||||
var audioSource: MediaSource =
|
var audioSource: MediaSource =
|
||||||
DefaultMediaSourceFactory(dataSourceFactory)
|
DefaultMediaSourceFactory(dataSourceFactory)
|
||||||
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
|
.createMediaSource(
|
||||||
if (response.videoStreams[index].quality == "720p" || response.videoStreams[index].quality == "1080p" || response.videoStreams[index].quality == "480p") {
|
fromUri(response.audioStreams!![0].url!!)
|
||||||
|
)
|
||||||
|
if (response.videoStreams[index].quality == "720p" ||
|
||||||
|
response.videoStreams[index].quality == "1080p" ||
|
||||||
|
response.videoStreams[index].quality == "480p"
|
||||||
|
) {
|
||||||
audioSource =
|
audioSource =
|
||||||
ProgressiveMediaSource.Factory(dataSourceFactory)
|
ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||||
.createMediaSource(
|
.createMediaSource(
|
||||||
fromUri(
|
fromUri(
|
||||||
response.audioStreams!![
|
response.audioStreams[
|
||||||
getMostBitRate(
|
getMostBitRate(
|
||||||
response.audioStreams
|
response.audioStreams
|
||||||
)
|
)
|
||||||
@ -490,11 +507,14 @@ class PlayerFragment : Fragment() {
|
|||||||
var audioSource: MediaSource =
|
var audioSource: MediaSource =
|
||||||
DefaultMediaSourceFactory(dataSourceFactory)
|
DefaultMediaSourceFactory(dataSourceFactory)
|
||||||
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
|
.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(
|
.createMediaSource(
|
||||||
fromUri(
|
fromUri(
|
||||||
response.audioStreams!![
|
response.audioStreams[
|
||||||
getMostBitRate(
|
getMostBitRate(
|
||||||
response.audioStreams
|
response.audioStreams
|
||||||
)
|
)
|
||||||
@ -528,13 +548,15 @@ class PlayerFragment : Fragment() {
|
|||||||
videosNameArray,
|
videosNameArray,
|
||||||
DialogInterface.OnClickListener { _, which ->
|
DialogInterface.OnClickListener { _, which ->
|
||||||
whichQuality = which
|
whichQuality = which
|
||||||
if (response.subtitles!!.isNotEmpty()) {
|
if (response.subtitles.isNotEmpty()) {
|
||||||
var subtitle =
|
var subtitle =
|
||||||
mutableListOf<SubtitleConfiguration>()
|
mutableListOf<SubtitleConfiguration>()
|
||||||
subtitle?.add(
|
subtitle.add(
|
||||||
SubtitleConfiguration.Builder(response.subtitles!![0].url!!.toUri())
|
SubtitleConfiguration.Builder(
|
||||||
.setMimeType(response.subtitles!![0].mimeType!!) // The correct MIME type (required).
|
response.subtitles[0].url!!.toUri()
|
||||||
.setLanguage(response.subtitles!![0].code) // The subtitle language (optional).
|
)
|
||||||
|
.setMimeType(response.subtitles[0].mimeType!!) // The correct MIME type (required).
|
||||||
|
.setLanguage(response.subtitles[0].code) // The subtitle language (optional).
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -556,13 +578,18 @@ class PlayerFragment : Fragment() {
|
|||||||
.createMediaSource(videoItem)
|
.createMediaSource(videoItem)
|
||||||
var audioSource: MediaSource =
|
var audioSource: MediaSource =
|
||||||
DefaultMediaSourceFactory(dataSourceFactory)
|
DefaultMediaSourceFactory(dataSourceFactory)
|
||||||
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
|
.createMediaSource(
|
||||||
if (response.videoStreams[which - 1].quality == "720p" || response.videoStreams[which - 1].quality == "1080p" || response.videoStreams[which - 1].quality == "480p") {
|
fromUri(response.audioStreams!![0].url!!)
|
||||||
|
)
|
||||||
|
if (response.videoStreams[which - 1].quality == "720p" ||
|
||||||
|
response.videoStreams[which - 1].quality == "1080p" ||
|
||||||
|
response.videoStreams[which - 1].quality == "480p"
|
||||||
|
) {
|
||||||
audioSource =
|
audioSource =
|
||||||
ProgressiveMediaSource.Factory(dataSourceFactory)
|
ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||||
.createMediaSource(
|
.createMediaSource(
|
||||||
fromUri(
|
fromUri(
|
||||||
response.audioStreams!![
|
response.audioStreams[
|
||||||
getMostBitRate(
|
getMostBitRate(
|
||||||
response.audioStreams
|
response.audioStreams
|
||||||
)
|
)
|
||||||
@ -579,14 +606,17 @@ class PlayerFragment : Fragment() {
|
|||||||
videosNameArray[which]
|
videosNameArray[which]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val dialog = builder?.create()
|
val dialog = builder.create()
|
||||||
dialog?.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
// 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 onIsPlayingChanged(isPlaying: Boolean) {
|
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||||
if (isPlaying && SponsorBlockSettings.sponsorBlockEnabled) {
|
if (isPlaying && SponsorBlockSettings.sponsorBlockEnabled) {
|
||||||
exoPlayerView.postDelayed(this@PlayerFragment::checkForSegments, 100)
|
exoPlayerView.postDelayed(
|
||||||
|
this@PlayerFragment::checkForSegments,
|
||||||
|
100
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +626,8 @@ class PlayerFragment : Fragment() {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
exoPlayerView.keepScreenOn = !(
|
exoPlayerView.keepScreenOn = !(
|
||||||
playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED ||
|
playbackState == Player.STATE_IDLE ||
|
||||||
|
playbackState == Player.STATE_ENDED ||
|
||||||
!playWhenReady
|
!playWhenReady
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -692,7 +723,8 @@ class PlayerFragment : Fragment() {
|
|||||||
if (ActivityCompat.checkSelfPermission(
|
if (ActivityCompat.checkSelfPermission(
|
||||||
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
|
||||||
@ -711,7 +743,7 @@ class PlayerFragment : Fragment() {
|
|||||||
vidName.add("No video")
|
vidName.add("No video")
|
||||||
var vidUrl = arrayListOf<String>()
|
var vidUrl = arrayListOf<String>()
|
||||||
vidUrl.add("")
|
vidUrl.add("")
|
||||||
for (vid in response.videoStreams!!) {
|
for (vid in response.videoStreams) {
|
||||||
val name = vid.quality + " " + vid.format
|
val name = vid.quality + " " + vid.format
|
||||||
vidName.add(name)
|
vidName.add(name)
|
||||||
vidUrl.add(vid.url!!)
|
vidUrl.add(vid.url!!)
|
||||||
@ -874,10 +906,6 @@ class PlayerFragment : Fragment() {
|
|||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchComments() {
|
private fun fetchComments() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val commentsResponse = try {
|
val commentsResponse = try {
|
||||||
@ -914,7 +942,7 @@ class PlayerFragment : Fragment() {
|
|||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
nextPage = response.nextpage
|
nextPage = response.nextpage
|
||||||
commentsAdapter?.updateItems(response.comments!!)
|
commentsAdapter?.updateItems(response.comments)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,7 +978,12 @@ class PlayerFragment : Fragment() {
|
|||||||
val scrollView = view?.findViewById<ScrollView>(R.id.player_scrollView)
|
val scrollView = view?.findViewById<ScrollView>(R.id.player_scrollView)
|
||||||
scrollView?.getHitRect(bounds)
|
scrollView?.getHitRect(bounds)
|
||||||
|
|
||||||
if (SDK_INT >= Build.VERSION_CODES.N && exoPlayer.isPlaying && (scrollView?.getLocalVisibleRect(bounds) == true || isFullScreen)) {
|
if (SDK_INT >= Build.VERSION_CODES.N &&
|
||||||
|
exoPlayer.isPlaying && (
|
||||||
|
scrollView?.getLocalVisibleRect(bounds) == true ||
|
||||||
|
isFullScreen
|
||||||
|
)
|
||||||
|
) {
|
||||||
requireActivity().enterPictureInPictureMode()
|
requireActivity().enterPictureInPictureMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ class PlaylistFragment : Fragment() {
|
|||||||
|
|
||||||
fetchPlaylist(view)
|
fetchPlaylist(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchPlaylist(view: View) {
|
private fun fetchPlaylist(view: View) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -66,14 +67,21 @@ class PlaylistFragment : Fragment() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
view.findViewById<TextView>(R.id.playlist_name).text = response.name
|
view.findViewById<TextView>(R.id.playlist_name).text = response.name
|
||||||
view.findViewById<TextView>(R.id.playlist_uploader).text = response.uploader
|
view.findViewById<TextView>(R.id.playlist_uploader).text = response.uploader
|
||||||
view.findViewById<TextView>(R.id.playlist_totVideos).text = response.videos.toString() + " Videos"
|
view.findViewById<TextView>(R.id.playlist_totVideos).text =
|
||||||
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
response.videos.toString() + " Videos"
|
||||||
|
val sharedPref2 =
|
||||||
|
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
|
||||||
val user = sharedPref2?.getString("username", "")
|
val user = sharedPref2?.getString("username", "")
|
||||||
var isOwner = false
|
var isOwner = false
|
||||||
if (response.uploaderUrl == null && response.uploader.equals(user, true)) {
|
if (response.uploaderUrl == null && response.uploader.equals(user, true)) {
|
||||||
isOwner = true
|
isOwner = true
|
||||||
}
|
}
|
||||||
playlistAdapter = PlaylistAdapter(response.relatedStreams!!.toMutableList(), playlist_id!!, isOwner, requireActivity())
|
playlistAdapter = PlaylistAdapter(
|
||||||
|
response.relatedStreams!!.toMutableList(),
|
||||||
|
playlist_id!!,
|
||||||
|
isOwner,
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
view.findViewById<RecyclerView>(R.id.playlist_recView).adapter = playlistAdapter
|
view.findViewById<RecyclerView>(R.id.playlist_recView).adapter = playlistAdapter
|
||||||
val scrollView = view.findViewById<ScrollView>(R.id.playlist_scrollview)
|
val scrollView = view.findViewById<ScrollView>(R.id.playlist_scrollview)
|
||||||
scrollView.viewTreeObserver
|
scrollView.viewTreeObserver
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import java.util.*
|
import java.util.LinkedList
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
class ResettableLazyManager {
|
class ResettableLazyManager {
|
||||||
@ -25,8 +25,10 @@ interface Resettable {
|
|||||||
fun reset()
|
fun reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: () -> PROPTYPE) : Resettable {
|
class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: () -> PROPTYPE) :
|
||||||
@Volatile var lazyHolder = makeInitBlock()
|
Resettable {
|
||||||
|
@Volatile
|
||||||
|
var lazyHolder = makeInitBlock()
|
||||||
|
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
|
||||||
return lazyHolder.value
|
return lazyHolder.value
|
||||||
@ -44,7 +46,8 @@ class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <PROPTYPE> resettableLazy(manager: ResettableLazyManager, init: () -> PROPTYPE): ResettableLazy<PROPTYPE> {
|
fun <PROPTYPE> resettableLazy(manager: ResettableLazyManager, init: () -> PROPTYPE):
|
||||||
|
ResettableLazy<PROPTYPE> {
|
||||||
return ResettableLazy(manager, init)
|
return ResettableLazy(manager, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,15 @@ import android.util.Log
|
|||||||
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.view.WindowManager
|
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.AutoCompleteTextView
|
import android.widget.AutoCompleteTextView
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView.*
|
import android.widget.TextView.GONE
|
||||||
|
import android.widget.TextView.OnEditorActionListener
|
||||||
|
import android.widget.TextView.VISIBLE
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
@ -25,11 +27,11 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import com.github.libretube.adapters.SearchAdapter
|
import com.github.libretube.adapters.SearchAdapter
|
||||||
import com.github.libretube.adapters.SearchHistoryAdapter
|
import com.github.libretube.adapters.SearchHistoryAdapter
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
private val TAG = "SearchFragment"
|
private val TAG = "SearchFragment"
|
||||||
@ -83,8 +85,7 @@ class SearchFragment : Fragment() {
|
|||||||
.setTitle(getString(R.string.choose_filter))
|
.setTitle(getString(R.string.choose_filter))
|
||||||
.setSingleChoiceItems(
|
.setSingleChoiceItems(
|
||||||
filterOptions, selectedFilter,
|
filterOptions, selectedFilter,
|
||||||
DialogInterface.OnClickListener {
|
DialogInterface.OnClickListener { _, id ->
|
||||||
_, id ->
|
|
||||||
tempSelectedItem = id
|
tempSelectedItem = id
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -154,8 +155,13 @@ class SearchFragment : Fragment() {
|
|||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
fetchSuggestions(s.toString(), autoTextView)
|
fetchSuggestions(s.toString(), autoTextView)
|
||||||
delay(1000)
|
delay(1000)
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences =
|
||||||
if (sharedPreferences.getBoolean("search_history_toggle", true)) addtohistory(s.toString())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
if (sharedPreferences.getBoolean(
|
||||||
|
"search_history_toggle",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
) addtohistory(s.toString())
|
||||||
fetchSearch(s.toString())
|
fetchSearch(s.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,10 +206,12 @@ class SearchFragment : Fragment() {
|
|||||||
Log.e(TAG, "HttpException, unexpected response")
|
Log.e(TAG, "HttpException, unexpected response")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, response)
|
val adapter =
|
||||||
|
ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, response)
|
||||||
autoTextView.setAdapter(adapter)
|
autoTextView.setAdapter(adapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchSearch(query: String) {
|
private fun fetchSearch(query: String) {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val response = try {
|
val response = try {
|
||||||
@ -232,7 +240,11 @@ class SearchFragment : Fragment() {
|
|||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
val response = try {
|
val response = try {
|
||||||
RetrofitInstance.api.getSearchResultsNextPage(query, apiSearchFilter, nextPage!!)
|
RetrofitInstance.api.getSearchResultsNextPage(
|
||||||
|
query,
|
||||||
|
apiSearchFilter,
|
||||||
|
nextPage!!
|
||||||
|
)
|
||||||
} 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")
|
||||||
@ -256,7 +268,7 @@ class SearchFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
requireActivity().window.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.*
|
import android.content.ContentResolver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@ -24,13 +28,13 @@ import androidx.preference.PreferenceFragmentCompat
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import org.json.JSONObject
|
|
||||||
import org.json.JSONTokener
|
|
||||||
import retrofit2.HttpException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.json.JSONTokener
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class SettingsActivity :
|
class SettingsActivity :
|
||||||
AppCompatActivity(),
|
AppCompatActivity(),
|
||||||
@ -61,7 +65,11 @@ class SettingsActivity :
|
|||||||
.registerOnSharedPreferenceChangeListener(this)
|
.registerOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, rootKey: String?) {}
|
override fun onSharedPreferenceChanged(
|
||||||
|
sharedPreferences: SharedPreferences?,
|
||||||
|
rootKey: String?
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
val TAG = "Settings"
|
val TAG = "Settings"
|
||||||
@ -71,66 +79,72 @@ class SettingsActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
|
getContent =
|
||||||
if (uri != null) {
|
registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
|
||||||
try {
|
if (uri != null) {
|
||||||
// Open a specific media item using ParcelFileDescriptor.
|
try {
|
||||||
val resolver: ContentResolver =
|
// Open a specific media item using ParcelFileDescriptor.
|
||||||
requireActivity()
|
val resolver: ContentResolver =
|
||||||
.contentResolver
|
requireActivity()
|
||||||
|
.contentResolver
|
||||||
|
|
||||||
// "rw" for read-and-write;
|
// "rw" for read-and-write;
|
||||||
// "rwt" for truncating or overwriting existing file contents.
|
// "rwt" for truncating or overwriting existing file contents.
|
||||||
// val readOnlyMode = "r"
|
// val readOnlyMode = "r"
|
||||||
// uri - I have got from onActivityResult
|
// uri - I have got from onActivityResult
|
||||||
val type = resolver.getType(uri)
|
val type = resolver.getType(uri)
|
||||||
|
|
||||||
var inputStream: InputStream? = resolver.openInputStream(uri)
|
var inputStream: InputStream? = resolver.openInputStream(uri)
|
||||||
val channels = ArrayList<String>()
|
val channels = ArrayList<String>()
|
||||||
if (type == "application/json") {
|
if (type == "application/json") {
|
||||||
val json = inputStream?.bufferedReader()?.readLines()?.get(0)
|
val json = inputStream?.bufferedReader()?.readLines()?.get(0)
|
||||||
val jsonObject = JSONTokener(json).nextValue() as JSONObject
|
val jsonObject = JSONTokener(json).nextValue() as JSONObject
|
||||||
Log.e(TAG, jsonObject.getJSONArray("subscriptions").toString())
|
Log.e(TAG, jsonObject.getJSONArray("subscriptions").toString())
|
||||||
for (i in 0 until jsonObject.getJSONArray("subscriptions").length()) {
|
for (
|
||||||
var url = jsonObject.getJSONArray("subscriptions").getJSONObject(i).getString("url")
|
i in 0 until jsonObject.getJSONArray("subscriptions")
|
||||||
url = url.replace("https://www.youtube.com/channel/", "")
|
.length()
|
||||||
Log.e(TAG, url)
|
) {
|
||||||
channels.add(url)
|
var url =
|
||||||
}
|
jsonObject.getJSONArray("subscriptions").getJSONObject(i)
|
||||||
} else {
|
.getString("url")
|
||||||
if (type == "application/zip") {
|
url = url.replace("https://www.youtube.com/channel/", "")
|
||||||
val zis = ZipInputStream(inputStream)
|
Log.e(TAG, url)
|
||||||
var entry: ZipEntry? = zis.nextEntry
|
channels.add(url)
|
||||||
while (entry != null) {
|
}
|
||||||
if (entry.name.endsWith(".csv")) {
|
} else {
|
||||||
inputStream = zis
|
if (type == "application/zip") {
|
||||||
break
|
val zis = ZipInputStream(inputStream)
|
||||||
|
var entry: ZipEntry? = zis.nextEntry
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.name.endsWith(".csv")) {
|
||||||
|
inputStream = zis
|
||||||
|
break
|
||||||
|
}
|
||||||
|
entry = zis.nextEntry
|
||||||
}
|
}
|
||||||
entry = zis.nextEntry
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inputStream?.bufferedReader()?.readLines()?.forEach {
|
inputStream?.bufferedReader()?.readLines()?.forEach {
|
||||||
if (it.isNotBlank()) {
|
if (it.isNotBlank()) {
|
||||||
val channelId = it.substringBefore(",")
|
val channelId = it.substringBefore(",")
|
||||||
if (channelId.length == 24)
|
if (channelId.length == 24)
|
||||||
channels.add(channelId)
|
channels.add(channelId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inputStream?.close()
|
||||||
|
|
||||||
|
subscribe(channels)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, e.toString())
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
R.string.error,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
inputStream?.close()
|
|
||||||
|
|
||||||
subscribe(channels)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, e.toString())
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
R.string.error,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +169,6 @@ class SettingsActivity :
|
|||||||
val login = findPreference<Preference>("login_register")
|
val login = findPreference<Preference>("login_register")
|
||||||
login?.setOnPreferenceClickListener {
|
login?.setOnPreferenceClickListener {
|
||||||
|
|
||||||
|
|
||||||
val newFragment = LoginDialog()
|
val newFragment = LoginDialog()
|
||||||
newFragment.show(childFragmentManager, "Login")
|
newFragment.show(childFragmentManager, "Login")
|
||||||
true
|
true
|
||||||
@ -200,7 +213,8 @@ class SettingsActivity :
|
|||||||
if (ActivityCompat.checkSelfPermission(
|
if (ActivityCompat.checkSelfPermission(
|
||||||
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
|
||||||
@ -245,7 +259,8 @@ class SettingsActivity :
|
|||||||
|
|
||||||
val clearHistory = findPreference<Preference>("clear_history")
|
val clearHistory = findPreference<Preference>("clear_history")
|
||||||
clearHistory?.setOnPreferenceClickListener {
|
clearHistory?.setOnPreferenceClickListener {
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
sharedPreferences.edit().remove("search_history").commit()
|
sharedPreferences.edit().remove("search_history").commit()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -269,7 +284,10 @@ class SettingsActivity :
|
|||||||
Html.fromHtml(licenseString)
|
Html.fromHtml(licenseString)
|
||||||
}
|
}
|
||||||
MaterialAlertDialogBuilder(view?.context!!)
|
MaterialAlertDialogBuilder(view?.context!!)
|
||||||
.setPositiveButton(getString(R.string.okay), DialogInterface.OnClickListener { _, _ -> })
|
.setPositiveButton(
|
||||||
|
getString(R.string.okay),
|
||||||
|
DialogInterface.OnClickListener { _, _ -> }
|
||||||
|
)
|
||||||
.setMessage(licenseHtml)
|
.setMessage(licenseHtml)
|
||||||
.create()
|
.create()
|
||||||
.show()
|
.show()
|
||||||
@ -327,7 +345,8 @@ class SettingsActivity :
|
|||||||
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.importSubscriptions(
|
RetrofitInstance.api.importSubscriptions(
|
||||||
false,
|
false,
|
||||||
sharedPref?.getString("token", "")!!,
|
sharedPref?.getString("token", "")!!,
|
||||||
@ -359,5 +378,4 @@ class SettingsActivity :
|
|||||||
intent = Intent(this, MainActivity::class.java)
|
intent = Intent(this, MainActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import androidx.constraintlayout.motion.widget.MotionLayout
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeSet? = null) : MotionLayout(context, attributeSet) {
|
class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeSet? = null) :
|
||||||
|
MotionLayout(context, attributeSet) {
|
||||||
|
|
||||||
private val viewToDetectTouch by lazy {
|
private val viewToDetectTouch by lazy {
|
||||||
findViewById<View>(R.id.main_container) // TODO move to Attributes
|
findViewById<View>(R.id.main_container) // TODO move to Attributes
|
||||||
|
@ -6,6 +6,7 @@ import androidx.preference.SwitchPreferenceCompat
|
|||||||
|
|
||||||
class SponsorBlockSettings : PreferenceFragmentCompat() {
|
class SponsorBlockSettings : PreferenceFragmentCompat() {
|
||||||
private val TAG = "SponsorBlockDialog"
|
private val TAG = "SponsorBlockDialog"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var sponsorBlockEnabled: Boolean = false
|
var sponsorBlockEnabled: Boolean = false
|
||||||
var sponsorsEnabled: Boolean = false
|
var sponsorsEnabled: Boolean = false
|
||||||
|
@ -9,7 +9,12 @@ import android.view.ViewGroup
|
|||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
import android.view.animation.RotateAnimation
|
import android.view.animation.RotateAnimation
|
||||||
import android.widget.*
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.ScrollView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@ -19,9 +24,8 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.github.libretube.adapters.SubscriptionAdapter
|
import com.github.libretube.adapters.SubscriptionAdapter
|
||||||
import com.github.libretube.adapters.SubscriptionChannelAdapter
|
import com.github.libretube.adapters.SubscriptionChannelAdapter
|
||||||
import retrofit2.HttpException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class Subscriptions : Fragment() {
|
class Subscriptions : Fragment() {
|
||||||
val TAG = "SubFragment"
|
val TAG = "SubFragment"
|
||||||
@ -60,7 +64,9 @@ class Subscriptions : Fragment() {
|
|||||||
|
|
||||||
var feedRecView = view.findViewById<RecyclerView>(R.id.sub_feed)
|
var feedRecView = view.findViewById<RecyclerView>(R.id.sub_feed)
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
val grid = sharedPreferences.getString("grid", resources.getInteger(R.integer.grid_items).toString())!!
|
val grid = sharedPreferences.getString(
|
||||||
|
"grid", resources.getInteger(R.integer.grid_items).toString()
|
||||||
|
)!!
|
||||||
feedRecView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
feedRecView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
||||||
fetchFeed(feedRecView, progressBar, view)
|
fetchFeed(feedRecView, progressBar, view)
|
||||||
|
|
||||||
@ -82,7 +88,7 @@ class Subscriptions : Fragment() {
|
|||||||
channelRecView.visibility = View.VISIBLE
|
channelRecView.visibility = View.VISIBLE
|
||||||
feedRecView.visibility = View.GONE
|
feedRecView.visibility = View.GONE
|
||||||
|
|
||||||
//toggle button
|
// toggle button
|
||||||
val rotate = RotateAnimation(
|
val rotate = RotateAnimation(
|
||||||
0F,
|
0F,
|
||||||
180F,
|
180F,
|
||||||
@ -96,12 +102,11 @@ class Subscriptions : Fragment() {
|
|||||||
rotate.fillAfter = true
|
rotate.fillAfter = true
|
||||||
val image = view.findViewById<ImageView>(R.id.toggle)
|
val image = view.findViewById<ImageView>(R.id.toggle)
|
||||||
image.startAnimation(rotate)
|
image.startAnimation(rotate)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
channelRecView.visibility = View.GONE
|
channelRecView.visibility = View.GONE
|
||||||
feedRecView.visibility = View.VISIBLE
|
feedRecView.visibility = View.VISIBLE
|
||||||
|
|
||||||
//toggle button
|
// toggle button
|
||||||
val image = view.findViewById<ImageView>(R.id.toggle)
|
val image = view.findViewById<ImageView>(R.id.toggle)
|
||||||
image.clearAnimation()
|
image.clearAnimation()
|
||||||
}
|
}
|
||||||
@ -143,7 +148,7 @@ class Subscriptions : Fragment() {
|
|||||||
}
|
}
|
||||||
if (response.isNotEmpty()) {
|
if (response.isNotEmpty()) {
|
||||||
subscriptionAdapter = SubscriptionAdapter(response)
|
subscriptionAdapter = SubscriptionAdapter(response)
|
||||||
feedRecView?.adapter = subscriptionAdapter
|
feedRecView.adapter = subscriptionAdapter
|
||||||
subscriptionAdapter?.updateItems()
|
subscriptionAdapter?.updateItems()
|
||||||
} else {
|
} else {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
@ -155,7 +160,8 @@ class Subscriptions : Fragment() {
|
|||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
text = getString(R.string.emptyList)
|
text = getString(R.string.emptyList)
|
||||||
}
|
}
|
||||||
view.findViewById<RelativeLayout>(R.id.loginOrRegister).visibility = View.VISIBLE
|
view.findViewById<RelativeLayout>(R.id.loginOrRegister)
|
||||||
|
.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
@ -181,7 +187,7 @@ class Subscriptions : Fragment() {
|
|||||||
refreshLayout?.isRefreshing = false
|
refreshLayout?.isRefreshing = false
|
||||||
}
|
}
|
||||||
if (response.isNotEmpty()) {
|
if (response.isNotEmpty()) {
|
||||||
channelRecView?.adapter = SubscriptionChannelAdapter(response.toMutableList())
|
channelRecView.adapter = SubscriptionChannelAdapter(response.toMutableList())
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, R.string.subscribeIsEmpty, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.subscribeIsEmpty, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@ -189,12 +195,14 @@ class Subscriptions : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.e(TAG, "Destroyed")
|
Log.e(TAG, "Destroyed")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
subscriptionAdapter = null
|
subscriptionAdapter = null
|
||||||
view?.findViewById<RecyclerView>(R.id.sub_feed)?.adapter = null
|
view?.findViewById<RecyclerView>(R.id.sub_feed)?.adapter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||||
this ?: return
|
this ?: return
|
||||||
if (!isAdded) return // Fragment not attached to an Activity
|
if (!isAdded) return // Fragment not attached to an Activity
|
||||||
|
@ -3,10 +3,11 @@ package com.github.libretube
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
|
|
||||||
fun updateAccentColor(context: Context) {
|
fun updateAccentColor(context: Context) {
|
||||||
val colorAccent = PreferenceManager.getDefaultSharedPreferences(context).getString("accent_color", "red")
|
val colorAccent =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).getString("accent_color", "red")
|
||||||
when (colorAccent) {
|
when (colorAccent) {
|
||||||
"my" -> context.setTheme(R.style.Theme_MY)
|
"my" -> context.setTheme(R.style.Theme_MY)
|
||||||
"red" -> context.setTheme(R.style.Theme_Red)
|
"red" -> context.setTheme(R.style.Theme_Red)
|
||||||
@ -18,7 +19,8 @@ fun updateAccentColor(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateThemeMode(context: Context) {
|
fun updateThemeMode(context: Context) {
|
||||||
val themeMode = PreferenceManager.getDefaultSharedPreferences(context).getString("theme_togglee", "A")
|
val themeMode =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).getString("theme_togglee", "A")
|
||||||
when (themeMode) {
|
when (themeMode) {
|
||||||
"A" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
"A" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
"L" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
"L" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
@ -15,10 +15,12 @@ import com.github.libretube.formatShort
|
|||||||
import com.github.libretube.obj.StreamItem
|
import com.github.libretube.obj.StreamItem
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) : RecyclerView.Adapter<ChannelViewHolder>() {
|
class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) :
|
||||||
|
RecyclerView.Adapter<ChannelViewHolder>() {
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return videoFeed.size
|
return videoFeed.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItems(newItems: List<StreamItem>) {
|
fun updateItems(newItems: List<StreamItem>) {
|
||||||
videoFeed.addAll(newItems)
|
videoFeed.addAll(newItems)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
@ -33,8 +35,11 @@ class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) : RecyclerV
|
|||||||
override fun onBindViewHolder(holder: ChannelViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ChannelViewHolder, position: Int) {
|
||||||
val trending = videoFeed[position]
|
val trending = videoFeed[position]
|
||||||
holder.v.findViewById<TextView>(R.id.channel_description).text = trending.title
|
holder.v.findViewById<TextView>(R.id.channel_description).text = trending.title
|
||||||
holder.v.findViewById<TextView>(R.id.channel_views).text = trending.views.formatShort() + " • " + DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
holder.v.findViewById<TextView>(R.id.channel_views).text =
|
||||||
holder.v.findViewById<TextView>(R.id.channel_duration).text = DateUtils.formatElapsedTime(trending.duration!!)
|
trending.views.formatShort() + " • " +
|
||||||
|
DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
||||||
|
holder.v.findViewById<TextView>(R.id.channel_duration).text =
|
||||||
|
DateUtils.formatElapsedTime(trending.duration!!)
|
||||||
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.channel_thumbnail)
|
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.channel_thumbnail)
|
||||||
Picasso.get().load(trending.thumbnail).into(thumbnailImage)
|
Picasso.get().load(trending.thumbnail).into(thumbnailImage)
|
||||||
holder.v.setOnClickListener {
|
holder.v.setOnClickListener {
|
||||||
@ -52,6 +57,7 @@ class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) : RecyclerV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class ChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import com.github.libretube.formatShort
|
|||||||
import com.github.libretube.obj.Comment
|
import com.github.libretube.obj.Comment
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class CommentsAdapter(private val comments: MutableList<Comment>) : RecyclerView.Adapter<ViewHolder>() {
|
class CommentsAdapter(private val comments: MutableList<Comment>) :
|
||||||
|
RecyclerView.Adapter<ViewHolder>() {
|
||||||
|
|
||||||
fun updateItems(newItems: List<Comment>) {
|
fun updateItems(newItems: List<Comment>) {
|
||||||
var commentsSize = comments.size
|
var commentsSize = comments.size
|
||||||
@ -23,16 +24,21 @@ class CommentsAdapter(private val comments: MutableList<Comment>) : RecyclerView
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
var commentsView = LayoutInflater.from(parent.context).inflate(R.layout.comments_row, parent, false)
|
var commentsView =
|
||||||
|
LayoutInflater.from(parent.context).inflate(R.layout.comments_row, parent, false)
|
||||||
return ViewHolder(commentsView)
|
return ViewHolder(commentsView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.v.findViewById<TextView>(R.id.comment_infos).text = comments[position].author.toString() + " • " + comments[position].commentedTime.toString()
|
holder.v.findViewById<TextView>(R.id.comment_infos).text =
|
||||||
holder.v.findViewById<TextView>(R.id.comment_text).text = comments[position].commentText.toString()
|
comments[position].author.toString() +
|
||||||
|
" • " + comments[position].commentedTime.toString()
|
||||||
|
holder.v.findViewById<TextView>(R.id.comment_text).text =
|
||||||
|
comments[position].commentText.toString()
|
||||||
val channelImage = holder.v.findViewById<ImageView>(R.id.commentor_image)
|
val channelImage = holder.v.findViewById<ImageView>(R.id.commentor_image)
|
||||||
Picasso.get().load(comments[position].thumbnail).fit().centerCrop().into(channelImage)
|
Picasso.get().load(comments[position].thumbnail).fit().centerCrop().into(channelImage)
|
||||||
holder.v.findViewById<TextView>(R.id.likes_textView).text = comments[position].likeCount?.toLong().formatShort()
|
holder.v.findViewById<TextView>(R.id.likes_textView).text =
|
||||||
|
comments[position].likeCount?.toLong().formatShort()
|
||||||
if (comments[position].verified == true) {
|
if (comments[position].verified == true) {
|
||||||
holder.v.findViewById<ImageView>(R.id.verified_imageView).visibility = View.VISIBLE
|
holder.v.findViewById<ImageView>(R.id.verified_imageView).visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class PlaylistAdapter(
|
|||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return videoFeed.size
|
return videoFeed.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItems(newItems: List<StreamItem>) {
|
fun updateItems(newItems: List<StreamItem>) {
|
||||||
videoFeed.addAll(newItems)
|
videoFeed.addAll(newItems)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
@ -48,7 +49,8 @@ class PlaylistAdapter(
|
|||||||
val streamItem = videoFeed[position]
|
val streamItem = videoFeed[position]
|
||||||
holder.v.findViewById<TextView>(R.id.playlist_title).text = streamItem.title
|
holder.v.findViewById<TextView>(R.id.playlist_title).text = streamItem.title
|
||||||
holder.v.findViewById<TextView>(R.id.playlist_description).text = streamItem.uploaderName
|
holder.v.findViewById<TextView>(R.id.playlist_description).text = streamItem.uploaderName
|
||||||
holder.v.findViewById<TextView>(R.id.playlist_duration).text = DateUtils.formatElapsedTime(streamItem.duration!!)
|
holder.v.findViewById<TextView>(R.id.playlist_duration).text =
|
||||||
|
DateUtils.formatElapsedTime(streamItem.duration!!)
|
||||||
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.playlist_thumbnail)
|
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.playlist_thumbnail)
|
||||||
Picasso.get().load(streamItem.thumbnail).into(thumbnailImage)
|
Picasso.get().load(streamItem.thumbnail).into(thumbnailImage)
|
||||||
holder.v.setOnClickListener {
|
holder.v.setOnClickListener {
|
||||||
@ -68,17 +70,24 @@ class PlaylistAdapter(
|
|||||||
val delete = holder.v.findViewById<ImageView>(R.id.delete_playlist)
|
val delete = holder.v.findViewById<ImageView>(R.id.delete_playlist)
|
||||||
delete.visibility = View.VISIBLE
|
delete.visibility = View.VISIBLE
|
||||||
delete.setOnClickListener {
|
delete.setOnClickListener {
|
||||||
val sharedPref = holder.v.context.getSharedPreferences("token", Context.MODE_PRIVATE)
|
val sharedPref = holder.v.context.getSharedPreferences(
|
||||||
|
"token",
|
||||||
|
Context.MODE_PRIVATE
|
||||||
|
)
|
||||||
val token = sharedPref?.getString("token", "")!!
|
val token = sharedPref?.getString("token", "")!!
|
||||||
removeFromPlaylist(token, position)
|
removeFromPlaylist(token, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeFromPlaylist(token: String, position: Int) {
|
private fun removeFromPlaylist(token: String, position: Int) {
|
||||||
fun run() {
|
fun run() {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val response = try {
|
val response = try {
|
||||||
RetrofitInstance.api.removeFromPlaylist(token, PlaylistId(playlistId = playlistId, index = position))
|
RetrofitInstance.api.removeFromPlaylist(
|
||||||
|
token,
|
||||||
|
PlaylistId(playlistId = playlistId, index = position)
|
||||||
|
)
|
||||||
} 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")
|
||||||
@ -107,6 +116,7 @@ class PlaylistAdapter(
|
|||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlaylistViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class PlaylistViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ import com.github.libretube.obj.PlaylistId
|
|||||||
import com.github.libretube.obj.Playlists
|
import com.github.libretube.obj.Playlists
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class PlaylistsAdapter(
|
class PlaylistsAdapter(
|
||||||
private val playlists: MutableList<Playlists>,
|
private val playlists: MutableList<Playlists>,
|
||||||
@ -30,6 +30,7 @@ class PlaylistsAdapter(
|
|||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return playlists.size
|
return playlists.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItems(newItems: List<Playlists>) {
|
fun updateItems(newItems: List<Playlists>) {
|
||||||
playlists.addAll(newItems)
|
playlists.addAll(newItems)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
@ -51,7 +52,10 @@ class PlaylistsAdapter(
|
|||||||
builder.setTitle(R.string.deletePlaylist)
|
builder.setTitle(R.string.deletePlaylist)
|
||||||
builder.setMessage(R.string.areYouSure)
|
builder.setMessage(R.string.areYouSure)
|
||||||
builder.setPositiveButton(R.string.yes) { dialog, which ->
|
builder.setPositiveButton(R.string.yes) { dialog, which ->
|
||||||
val sharedPref = holder.v.context.getSharedPreferences("token", Context.MODE_PRIVATE)
|
val sharedPref = holder.v.context.getSharedPreferences(
|
||||||
|
"token",
|
||||||
|
Context.MODE_PRIVATE
|
||||||
|
)
|
||||||
val token = sharedPref?.getString("token", "")!!
|
val token = sharedPref?.getString("token", "")!!
|
||||||
deletePlaylist(playlist.id!!, token, position)
|
deletePlaylist(playlist.id!!, token, position)
|
||||||
}
|
}
|
||||||
@ -66,6 +70,7 @@ class PlaylistsAdapter(
|
|||||||
activity.navController.navigate(R.id.playlistFragment, bundle)
|
activity.navController.navigate(R.id.playlistFragment, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deletePlaylist(id: String, token: String, position: Int) {
|
private fun deletePlaylist(id: String, token: String, position: Int) {
|
||||||
fun run() {
|
fun run() {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
@ -99,6 +104,7 @@ class PlaylistsAdapter(
|
|||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlaylistsViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class PlaylistsViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ import com.github.libretube.formatShort
|
|||||||
import com.github.libretube.obj.SearchItem
|
import com.github.libretube.obj.SearchItem
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class SearchAdapter(private val searchItems: MutableList<SearchItem>) : RecyclerView.Adapter<CustomViewHolder1>() {
|
class SearchAdapter(private val searchItems: MutableList<SearchItem>) :
|
||||||
|
RecyclerView.Adapter<CustomViewHolder1>() {
|
||||||
|
|
||||||
fun updateItems(newItems: List<SearchItem>) {
|
fun updateItems(newItems: List<SearchItem>) {
|
||||||
var searchItemsSize = searchItems.size
|
var searchItemsSize = searchItems.size
|
||||||
@ -54,6 +55,7 @@ class SearchAdapter(private val searchItems: MutableList<SearchItem>) : Recycler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
|
|
||||||
private fun bindWatch(item: SearchItem) {
|
private fun bindWatch(item: SearchItem) {
|
||||||
@ -64,11 +66,16 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
|||||||
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
|
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
|
||||||
Picasso.get().load(item.uploaderAvatar).fit().centerCrop().into(channelImage)
|
Picasso.get().load(item.uploaderAvatar).fit().centerCrop().into(channelImage)
|
||||||
val title = v.findViewById<TextView>(R.id.search_description)
|
val title = v.findViewById<TextView>(R.id.search_description)
|
||||||
title.text = if (item.title!!.length > 60) item.title?.substring(0, 60) + "..." else item.title
|
title.text =
|
||||||
|
if (item.title!!.length > 60) item.title?.substring(0, 60) + "..." else item.title
|
||||||
val views = v.findViewById<TextView>(R.id.search_views)
|
val views = v.findViewById<TextView>(R.id.search_views)
|
||||||
val viewsString = if (item.views?.toInt() != -1) item.views.formatShort() else ""
|
val viewsString = if (item.views?.toInt() != -1) item.views.formatShort() else ""
|
||||||
val uploadDate = if (item.uploadedDate != null) item.uploadedDate else ""
|
val uploadDate = if (item.uploadedDate != null) item.uploadedDate else ""
|
||||||
views.text = if (viewsString != "" && uploadDate != "") viewsString + " • " + uploadDate else viewsString + uploadDate
|
views.text =
|
||||||
|
if (viewsString != "" && uploadDate != "")
|
||||||
|
"$viewsString • $uploadDate"
|
||||||
|
else
|
||||||
|
viewsString + uploadDate
|
||||||
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
|
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
|
||||||
channelName.text = item.uploaderName
|
channelName.text = item.uploaderName
|
||||||
v.setOnClickListener {
|
v.setOnClickListener {
|
||||||
@ -90,13 +97,17 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
|||||||
activity.navController.navigate(R.id.channel, bundle)
|
activity.navController.navigate(R.id.channel, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindChannel(item: SearchItem) {
|
private fun bindChannel(item: SearchItem) {
|
||||||
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
|
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
|
||||||
Picasso.get().load(item.thumbnail).fit().centerCrop().into(channelImage)
|
Picasso.get().load(item.thumbnail).fit().centerCrop().into(channelImage)
|
||||||
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
|
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
|
||||||
channelName.text = item.name
|
channelName.text = item.name
|
||||||
val channelViews = v.findViewById<TextView>(R.id.search_views)
|
val channelViews = v.findViewById<TextView>(R.id.search_views)
|
||||||
channelViews.text = v.context.getString(R.string.subscribers, item.subscribers.formatShort()) + " • " + v.context.getString(R.string.videoCount, item.videos.toString())
|
channelViews.text = v.context.getString(
|
||||||
|
R.string.subscribers,
|
||||||
|
item.subscribers.formatShort()
|
||||||
|
) + " • " + v.context.getString(R.string.videoCount, item.videos.toString())
|
||||||
v.setOnClickListener {
|
v.setOnClickListener {
|
||||||
val activity = v.context as MainActivity
|
val activity = v.context as MainActivity
|
||||||
val bundle = bundleOf("channel_id" to item.url)
|
val bundle = bundleOf("channel_id" to item.url)
|
||||||
@ -104,6 +115,7 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
|||||||
}
|
}
|
||||||
// todo sub button
|
// todo sub button
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPlaylist(item: SearchItem) {
|
private fun bindPlaylist(item: SearchItem) {
|
||||||
val playlistImage = v.findViewById<ImageView>(R.id.search_thumbnail)
|
val playlistImage = v.findViewById<ImageView>(R.id.search_thumbnail)
|
||||||
Picasso.get().load(item.thumbnail).fit().centerCrop().into(playlistImage)
|
Picasso.get().load(item.thumbnail).fit().centerCrop().into(playlistImage)
|
||||||
@ -114,7 +126,9 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
|
|||||||
val playlistChannelName = v.findViewById<TextView>(R.id.search_name)
|
val playlistChannelName = v.findViewById<TextView>(R.id.search_name)
|
||||||
playlistChannelName.text = item.uploaderName
|
playlistChannelName.text = item.uploaderName
|
||||||
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_videos)
|
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_videos)
|
||||||
if (item.videos?.toInt() != -1) playlistVideosNumber.text = v.context.getString(R.string.videoCount, item.videos.toString())
|
if (item.videos?.toInt() != -1)
|
||||||
|
playlistVideosNumber.text =
|
||||||
|
v.context.getString(R.string.videoCount, item.videos.toString())
|
||||||
v.setOnClickListener {
|
v.setOnClickListener {
|
||||||
// playlist clicked
|
// playlist clicked
|
||||||
val activity = v.context as MainActivity
|
val activity = v.context as MainActivity
|
||||||
|
@ -18,7 +18,8 @@ import com.github.libretube.formatShort
|
|||||||
import com.github.libretube.obj.StreamItem
|
import com.github.libretube.obj.StreamItem
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class SubscriptionAdapter(private val videoFeed: List<StreamItem>) : RecyclerView.Adapter<SubscriptionViewHolder>() {
|
class SubscriptionAdapter(private val videoFeed: List<StreamItem>) :
|
||||||
|
RecyclerView.Adapter<SubscriptionViewHolder>() {
|
||||||
// private var limitedVideoFeed: MutableList<String> = [""].toMutableList()
|
// private var limitedVideoFeed: MutableList<String> = [""].toMutableList()
|
||||||
var i = 0
|
var i = 0
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
@ -42,9 +43,13 @@ class SubscriptionAdapter(private val videoFeed: List<StreamItem>) : RecyclerVie
|
|||||||
override fun onBindViewHolder(holder: SubscriptionViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: SubscriptionViewHolder, position: Int) {
|
||||||
val trending = videoFeed[position]
|
val trending = videoFeed[position]
|
||||||
holder.v.findViewById<TextView>(R.id.textView_title).text = trending.title
|
holder.v.findViewById<TextView>(R.id.textView_title).text = trending.title
|
||||||
holder.v.findViewById<TextView>(R.id.textView_channel).text = trending.uploaderName + " • " + trending.views.formatShort() + " • " + DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
holder.v.findViewById<TextView>(R.id.textView_channel).text =
|
||||||
|
trending.uploaderName + " • " +
|
||||||
|
trending.views.formatShort() + " • " +
|
||||||
|
DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
||||||
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.thumbnail)
|
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.thumbnail)
|
||||||
holder.v.findViewById<TextView>(R.id.thumbnail_duration).text = DateUtils.formatElapsedTime(trending.duration!!)
|
holder.v.findViewById<TextView>(R.id.thumbnail_duration).text =
|
||||||
|
DateUtils.formatElapsedTime(trending.duration!!)
|
||||||
val channelImage = holder.v.findViewById<ImageView>(R.id.channel_image)
|
val channelImage = holder.v.findViewById<ImageView>(R.id.channel_image)
|
||||||
channelImage.setOnClickListener {
|
channelImage.setOnClickListener {
|
||||||
val activity = holder.v.context as MainActivity
|
val activity = holder.v.context as MainActivity
|
||||||
@ -76,6 +81,7 @@ class SubscriptionAdapter(private val videoFeed: List<StreamItem>) : RecyclerVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscriptionViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class SubscriptionViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@ import com.github.libretube.R
|
|||||||
import com.github.libretube.obj.Subscription
|
import com.github.libretube.obj.Subscription
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscription>) : RecyclerView.Adapter<SubscriptionChannelViewHolder>() {
|
class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscription>) :
|
||||||
|
RecyclerView.Adapter<SubscriptionChannelViewHolder>() {
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return subscriptions.size
|
return subscriptions.size
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionChannelViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
|
||||||
|
SubscriptionChannelViewHolder {
|
||||||
val layoutInflater = LayoutInflater.from(parent.context)
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
val cell = layoutInflater.inflate(R.layout.channel_subscription_row, parent, false)
|
val cell = layoutInflater.inflate(R.layout.channel_subscription_row, parent, false)
|
||||||
return SubscriptionChannelViewHolder(cell)
|
return SubscriptionChannelViewHolder(cell)
|
||||||
@ -35,6 +37,7 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscrip
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscriptionChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class SubscriptionChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ import com.github.libretube.formatShort
|
|||||||
import com.github.libretube.obj.StreamItem
|
import com.github.libretube.obj.StreamItem
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class TrendingAdapter(private val videoFeed: List<StreamItem>) : RecyclerView.Adapter<CustomViewHolder>() {
|
class TrendingAdapter(private val videoFeed: List<StreamItem>) :
|
||||||
|
RecyclerView.Adapter<CustomViewHolder>() {
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return videoFeed.size
|
return videoFeed.size
|
||||||
}
|
}
|
||||||
@ -32,9 +33,13 @@ class TrendingAdapter(private val videoFeed: List<StreamItem>) : RecyclerView.Ad
|
|||||||
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
|
||||||
val trending = videoFeed[position]
|
val trending = videoFeed[position]
|
||||||
holder.v.findViewById<TextView>(R.id.textView_title).text = trending.title
|
holder.v.findViewById<TextView>(R.id.textView_title).text = trending.title
|
||||||
holder.v.findViewById<TextView>(R.id.textView_channel).text = trending.uploaderName + " • " + trending.views.formatShort() + " • " + DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
holder.v.findViewById<TextView>(R.id.textView_channel).text =
|
||||||
|
trending.uploaderName + " • " +
|
||||||
|
trending.views.formatShort() + " • " +
|
||||||
|
DateUtils.getRelativeTimeSpanString(trending.uploaded!!)
|
||||||
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.thumbnail)
|
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.thumbnail)
|
||||||
holder.v.findViewById<TextView>(R.id.thumbnail_duration).text = DateUtils.formatElapsedTime(trending.duration!!)
|
holder.v.findViewById<TextView>(R.id.thumbnail_duration).text =
|
||||||
|
DateUtils.formatElapsedTime(trending.duration!!)
|
||||||
val channelImage = holder.v.findViewById<ImageView>(R.id.channel_image)
|
val channelImage = holder.v.findViewById<ImageView>(R.id.channel_image)
|
||||||
channelImage.setOnClickListener {
|
channelImage.setOnClickListener {
|
||||||
val activity = holder.v.context as MainActivity
|
val activity = holder.v.context as MainActivity
|
||||||
@ -73,6 +78,7 @@ class TrendingAdapter(private val videoFeed: List<StreamItem>) : RecyclerView.Ad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
class CustomViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
|
||||||
init {
|
init {
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user