Fix all linting errors.

This commit is contained in:
Kavin 2022-05-21 09:02:04 +01:00
parent 940a3b20e7
commit 057cf3f02f
No known key found for this signature in database
GPG Key ID: 49451E4482CC5BCD
30 changed files with 536 additions and 253 deletions

View File

@ -2,7 +2,7 @@ package com.github.libretube
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.*
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -6,15 +6,19 @@ import android.os.Bundle
import android.util.Log
import android.util.TypedValue
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.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.github.libretube.obj.PlaylistId
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import retrofit2.HttpException
import java.io.IOException
import retrofit2.HttpException
class AddtoPlaylistDialog : DialogFragment() {
private val TAG = "AddToPlaylistDialog"
@ -49,6 +53,7 @@ class AddtoPlaylistDialog : DialogFragment() {
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
private fun fetchPlaylists() {
fun run() {
lifecycleScope.launchWhenCreated {
@ -69,8 +74,11 @@ class AddtoPlaylistDialog : DialogFragment() {
for (playlist in response) {
names.add(playlist.name!!)
}
val arrayAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
val arrayAdapter =
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
arrayAdapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
spinner.adapter = arrayAdapter
runOnUiThread {
button.setOnClickListener {
@ -83,6 +91,7 @@ class AddtoPlaylistDialog : DialogFragment() {
}
run()
}
private fun addToPlaylist(playlistId: String) {
fun run() {
lifecycleScope.launchWhenCreated {
@ -108,6 +117,7 @@ class AddtoPlaylistDialog : DialogFragment() {
}
run()
}
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity

View File

@ -3,7 +3,6 @@ package com.github.libretube
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.text.TextUtils.substring
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@ -94,7 +93,10 @@ class ChannelFragment : Fragment() {
lifecycleScope.launchWhenCreated {
val response = try {
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) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
@ -131,7 +133,10 @@ class ChannelFragment : Fragment() {
lifecycleScope.launchWhenCreated {
val response = try {
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) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
@ -145,12 +150,16 @@ class ChannelFragment : Fragment() {
}
run()
}
private fun unsubscribe() {
fun run() {
lifecycleScope.launchWhenCreated {
val response = try {
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) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
@ -186,12 +195,19 @@ class ChannelFragment : Fragment() {
runOnUiThread {
view.findViewById<ScrollView>(R.id.channel_scrollView).visibility = View.VISIBLE
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)
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)
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 channelImage = view.findViewById<ImageView>(R.id.channel_image)
Picasso.get().load(response.bannerUrl).into(bannerImage)
@ -203,6 +219,7 @@ class ChannelFragment : Fragment() {
}
run()
}
private fun fetchNextPage() {
fun run() {
@ -227,6 +244,7 @@ class ChannelFragment : Fragment() {
}
run()
}
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity

View File

@ -12,6 +12,7 @@ import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import com.google.android.material.textfield.TextInputEditText
class CreatePlaylistDialog : DialogFragment() {
override fun onCreateView(
@ -35,7 +36,7 @@ class CreatePlaylistDialog : DialogFragment() {
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)
createPlaylistBtn.setOnClickListener {
var listName = playlistName.text.toString()

View File

@ -6,7 +6,13 @@ import android.os.Bundle
import android.util.Log
import android.util.TypedValue
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.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -35,7 +41,11 @@ class DownloadDialog : DialogFragment() {
val inflater = requireActivity().layoutInflater
var view: View = inflater.inflate(R.layout.dialog_download, null)
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)
videoSpinner.adapter = videoArrayAdapter
videoSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@ -48,10 +58,15 @@ class DownloadDialog : DialogFragment() {
selectedVideo = position
Log.d(TAG, selectedVideo.toString())
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
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)
audioSpinner.adapter = audioArrayAdapter
audioSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@ -64,6 +79,7 @@ class DownloadDialog : DialogFragment() {
selectedAudio = position
Log.d(TAG, selectedAudio.toString())
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
val radioGroup = view.findViewById<RadioGroup>(R.id.radioGp)
@ -97,6 +113,7 @@ class DownloadDialog : DialogFragment() {
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
override fun onDestroy() {
vidName.clear()
vidUrl.clear()

View File

@ -1,6 +1,11 @@
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.Context
import android.content.Intent
@ -9,6 +14,7 @@ import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Environment.DIRECTORY_DOWNLOADS
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
@ -17,6 +23,7 @@ import com.arthenica.ffmpegkit.FFmpegKit
import java.io.File
var IS_DOWNLOAD_RUNNING = false
class DownloadService : Service() {
val TAG = "DownloadService"
private var downloadId: Long = -1
@ -25,6 +32,7 @@ class DownloadService : Service() {
private lateinit var audioUrl: String
private lateinit var extension: String
private var duration: Int = 0
// private lateinit var command: String
private lateinit var audioDir: File
private lateinit var videoDir: File
@ -81,6 +89,7 @@ class DownloadService : Service() {
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
@ -101,7 +110,10 @@ class DownloadService : Service() {
videoDir = File(f, "$videoId-video")
try {
Log.e(TAG, "Directory make")
registerReceiver(onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
registerReceiver(
onDownloadComplete,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
)
val request: DownloadManager.Request =
DownloadManager.Request(Uri.parse(videoUrl))
.setTitle("Video") // Title of the Download Notification
@ -113,7 +125,9 @@ class DownloadService : Service() {
val downloadManager: DownloadManager =
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request)
if (audioUrl == "") { downloadId = 0L }
if (audioUrl == "") {
downloadId = 0L
}
} catch (e: IllegalArgumentException) {
Log.e(TAG, "download error $e")
try {
@ -155,9 +169,12 @@ class DownloadService : Service() {
val downloadManager: DownloadManager =
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadManager.enqueue(request)
} catch (e: Exception) {}
} catch (e: Exception) {
}
} else if (downloadId == 0L) {
val libreTube = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LibreTube")
val libreTube = File(
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "LibreTube"
)
if (!libreTube.exists()) {
libreTube.mkdirs()
Log.e(TAG, "libreTube Directory make")
@ -191,7 +208,8 @@ class DownloadService : Service() {
session.failStackTrace
)
)
val path = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
val path =
applicationContext.getExternalFilesDir(DIRECTORY_DOWNLOADS)
val folder_main = ".tmp"
val f = File(path, folder_main)
f.deleteRecursively()
@ -243,10 +261,12 @@ class DownloadService : Service() {
notificationManager.createNotificationChannel(channel)
}
}
override fun onDestroy() {
try {
unregisterReceiver(onDownloadComplete)
} catch (e: Exception) {}
} catch (e: Exception) {
}
IS_DOWNLOAD_RUNNING = false
Log.d(TAG, "dl finished!")
super.onDestroy()

View File

@ -15,7 +15,6 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.github.libretube.adapters.TrendingAdapter
import java.io.IOException
import okhttp3.*
import retrofit2.HttpException
class Home : Fragment() {
@ -42,7 +41,10 @@ class Home : Fragment() {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
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())
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
fetchJson(progressbar, recyclerView)
@ -58,7 +60,8 @@ class Home : Fragment() {
fun run() {
lifecycleScope.launchWhenCreated {
val response = try {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext())
RetrofitInstance.api.getTrending(sharedPreferences.getString("region", "US")!!)
} catch (e: IOException) {
println(e)
@ -80,6 +83,7 @@ class Home : Fragment() {
}
run()
}
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity

View File

@ -52,8 +52,8 @@ class Library : Fragment() {
view.findViewById<ImageView>(R.id.boogh2).visibility = View.GONE
view.findViewById<TextView>(R.id.textLike2).visibility = View.GONE
fetchPlaylists(view)
refreshLayout?.isEnabled = true
refreshLayout?.setOnRefreshListener {
refreshLayout.isEnabled = true
refreshLayout.setOnRefreshListener {
Log.d(TAG, "hmm")
fetchPlaylists(view)
}
@ -66,7 +66,7 @@ class Library : Fragment() {
createPlaylist("$playlistName", view)
}
} else {
refreshLayout?.isEnabled = false
refreshLayout.isEnabled = false
view.findViewById<Button>(R.id.create_playlist).visibility = View.GONE
with(view.findViewById<ImageView>(R.id.boogh2)) {
visibility = View.VISIBLE
@ -81,7 +81,7 @@ class Library : Fragment() {
private fun fetchPlaylists(view: View) {
fun run() {
refreshLayout?.isRefreshing = true
refreshLayout.isRefreshing = true
lifecycleScope.launchWhenCreated {
val response = try {
RetrofitInstance.api.playlists(token)
@ -95,7 +95,7 @@ class Library : Fragment() {
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated
} finally {
refreshLayout?.isRefreshing = false
refreshLayout.isRefreshing = false
}
if (response.isNotEmpty()) {
runOnUiThread {
@ -106,7 +106,10 @@ class Library : Fragment() {
visibility = View.GONE
}
}
val playlistsAdapter = PlaylistsAdapter(response.toMutableList(), requireActivity())
val playlistsAdapter = PlaylistsAdapter(
response.toMutableList(),
requireActivity()
)
playlistRecyclerView.adapter = playlistsAdapter
} else {
runOnUiThread {
@ -124,6 +127,7 @@ class Library : Fragment() {
}
run()
}
private fun createPlaylist(name: String, view: View) {
fun run() {
lifecycleScope.launchWhenCreated {

View File

@ -15,8 +15,8 @@ import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.github.libretube.obj.Login
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import retrofit2.HttpException
import java.io.IOException
import retrofit2.HttpException
class LoginDialog : DialogFragment() {
private val TAG = "LoginDialog"
@ -35,7 +35,8 @@ class LoginDialog : DialogFragment() {
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
val user = sharedPref2?.getString("username", "")
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 {
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show()
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
@ -76,11 +77,11 @@ class LoginDialog : DialogFragment() {
)
view.findViewById<TextView>(R.id.title).text = appName
builder.setView(view)
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
private fun login(login: Login) {
fun run() {
lifecycleScope.launchWhenCreated {
@ -108,7 +109,8 @@ class LoginDialog : DialogFragment() {
putString("token", response.token)
apply()
}
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
val sharedPref2 =
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
with(sharedPref2!!.edit()) {
putString("username", login.username)
apply()
@ -119,6 +121,7 @@ class LoginDialog : DialogFragment() {
}
run()
}
private fun register(login: Login) {
fun run() {
lifecycleScope.launchWhenCreated {
@ -146,7 +149,8 @@ class LoginDialog : DialogFragment() {
putString("token", response.token)
apply()
}
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
val sharedPref2 =
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
with(sharedPref2!!.edit()) {
putString("username", login.username)
apply()

View File

@ -12,7 +12,10 @@ import android.os.Bundle
import android.os.Handler
import android.util.Log
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.widget.Button
import android.widget.LinearLayout
@ -40,25 +43,33 @@ class MainActivity : AppCompatActivity() {
DynamicColors.applyToActivityIfAvailable(this)
super.onCreate(savedInstanceState)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
RetrofitInstance.url = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
SponsorBlockSettings.sponsorBlockEnabled = sharedPreferences.getBoolean("sponsorblock_enabled_key", false)
SponsorBlockSettings.introEnabled = sharedPreferences.getBoolean("intro_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)
RetrofitInstance.url =
sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
SponsorBlockSettings.sponsorBlockEnabled =
sharedPreferences.getBoolean("sponsorblock_enabled_key", false)
SponsorBlockSettings.introEnabled =
sharedPreferences.getBoolean("intro_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)
updateThemeMode(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 isConnected = networkInfo != null && networkInfo.isConnected
if (!isConnected) {
setContentView(R.layout.activity_nointernet)
findViewById<Button>(R.id.retry_button).setOnClickListener() {
findViewById<Button>(R.id.retry_button).setOnClickListener {
recreate()
}
} else {
@ -137,10 +148,13 @@ class MainActivity : AppCompatActivity() {
if (data.host != null) {
if (data.path != null) {
// 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
channel = channel!!.replace("/c/", "")
channel = channel!!.replace("/user/", "")
channel = channel.replace("/user/", "")
val bundle = bundleOf("channel_id" to channel)
navController.navigate(R.id.channel, bundle)
} else if (data.path!!.contains("/playlist")) {
@ -157,11 +171,17 @@ class MainActivity : AppCompatActivity() {
playlist = playlist.replace("list=", "")
val bundle = bundleOf("playlist_id" to playlist)
navController.navigate(R.id.playlistFragment, bundle)
} else if (data.path!!.contains("/shorts/") || data.path!!.contains("/embed/") || data.path!!.contains("/v/")) {
var watch = data.path!!.replace("/shorts/", "").replace("/v/", "").replace("/embed/", "")
var bundle = Bundle()
} else if (data.path!!.contains("/shorts/") ||
data.path!!.contains("/embed/") ||
data.path!!.contains("/v/")
) {
val watch = data.path!!
.replace("/shorts/", "")
.replace("/v/", "")
.replace("/embed/", "")
val bundle = Bundle()
bundle.putString("videoId", watch)
var frag = PlayerFragment()
val frag = PlayerFragment()
frag.arguments = bundle
supportFragmentManager.beginTransaction()
.remove(PlayerFragment())
@ -241,7 +261,9 @@ class MainActivity : AppCompatActivity() {
isFullScreen = false
} else {
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()
}
}
@ -250,6 +272,7 @@ class MainActivity : AppCompatActivity() {
moveTaskToBack(true)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val orientation = newConfig.orientation
@ -261,6 +284,7 @@ class MainActivity : AppCompatActivity() {
setFullscreen()
}
}
private fun setFullscreen() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
@ -285,6 +309,7 @@ class MainActivity : AppCompatActivity() {
)
}
}
private fun unsetFullscreen() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
@ -299,7 +324,8 @@ class MainActivity : AppCompatActivity() {
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
@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() {
view?.let { activity?.hideKeyboard(it) }
}

View File

@ -1,7 +1,28 @@
package com.github.libretube
import com.github.libretube.obj.*
import retrofit2.http.*
import com.github.libretube.obj.Channel
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 {
@GET("trending")
@ -14,7 +35,10 @@ interface PipedApi {
suspend fun getComments(@Path("videoId") videoId: String): CommentsPage
@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}")
suspend fun getCommentsNextPage(
@ -75,10 +99,16 @@ interface PipedApi {
suspend fun subscriptions(@Header("Authorization") token: String): List<Subscription>
@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")
suspend fun unsubscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
suspend fun unsubscribe(
@Header("Authorization") token: String,
@Body subscribe: Subscribe
): Message
@POST("import")
suspend fun importSubscriptions(
@ -91,13 +121,22 @@ interface PipedApi {
suspend fun playlists(@Header("Authorization") token: String): List<Playlists>
@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")
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")
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")
suspend fun removeFromPlaylist(

View File

@ -1,12 +1,8 @@
package com.github.libretube
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 com.google.android.material.color.DynamicColors
class Player : Activity() {

View File

@ -22,7 +22,14 @@ import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
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.widget.ConstraintLayout
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.dialog.MaterialAlertDialogBuilder
import com.squareup.picasso.Picasso
import org.chromium.net.CronetEngine
import retrofit2.HttpException
import java.io.IOException
import java.net.URLEncoder
import java.util.concurrent.Executors
import kotlin.math.abs
import org.chromium.net.CronetEngine
import retrofit2.HttpException
var isFullScreen = false
@ -207,34 +214,37 @@ class PlayerFragment : Fragment() {
}
view.findViewById<RelativeLayout>(R.id.player_title_layout).setOnClickListener {
if (playerDescription.isVisible){
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
image.clearAnimation()
playerDescription.visibility = View.GONE
} else {
//toggle button
val rotate = RotateAnimation(
0F,
180F,
Animation.RELATIVE_TO_SELF,
0.5f,
Animation.RELATIVE_TO_SELF,
0.5f
)
rotate.duration = 100
rotate.interpolator = LinearInterpolator()
rotate.fillAfter = true
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
image.startAnimation(rotate)
playerDescription.visibility = View.VISIBLE
}
if (playerDescription.isVisible) {
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
image.clearAnimation()
playerDescription.visibility = View.GONE
} else {
// toggle button
val rotate = RotateAnimation(
0F,
180F,
Animation.RELATIVE_TO_SELF,
0.5f,
Animation.RELATIVE_TO_SELF,
0.5f
)
rotate.duration = 100
rotate.interpolator = LinearInterpolator()
rotate.fillAfter = true
val image = view.findViewById<ImageView>(R.id.player_description_arrow)
image.startAnimation(rotate)
playerDescription.visibility = View.VISIBLE
}
}
view.findViewById<com.google.android.material.card.MaterialCardView>(R.id.comments_toggle).setOnClickListener {
commentsRecView.visibility = if (commentsRecView.isVisible) View.GONE else View.VISIBLE
relatedRecView.visibility = if (relatedRecView.isVisible) View.GONE else View.VISIBLE
if (!commentsLoaded!!) fetchComments()
}
view.findViewById<com.google.android.material.card.MaterialCardView>(R.id.comments_toggle)
.setOnClickListener {
commentsRecView.visibility =
if (commentsRecView.isVisible) View.GONE else View.VISIBLE
relatedRecView.visibility =
if (relatedRecView.isVisible) View.GONE else View.VISIBLE
if (!commentsLoaded!!) fetchComments()
}
// FullScreen button trigger
view.findViewById<ImageButton>(R.id.fullscreen).setOnClickListener {
@ -266,8 +276,9 @@ class PlayerFragment : Fragment() {
scrollView.viewTreeObserver
.addOnScrollChangedListener {
if (scrollView.getChildAt(0).bottom
== (scrollView.height + scrollView.scrollY)
&& nextPage != null) {
== (scrollView.height + scrollView.scrollY) &&
nextPage != null
) {
fetchNextComments()
}
}
@ -276,8 +287,8 @@ class PlayerFragment : Fragment() {
commentsRecView.layoutManager = LinearLayoutManager(view.context)
commentsRecView.setItemViewCacheSize(20)
commentsRecView.setDrawingCacheEnabled(true)
commentsRecView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH)
commentsRecView.isDrawingCacheEnabled = true
commentsRecView.drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
relatedRecView = view.findViewById(R.id.player_recView)
relatedRecView.layoutManager =
@ -287,7 +298,8 @@ class PlayerFragment : Fragment() {
override fun onStop() {
try {
exoPlayer.release()
}catch (e: Exception){}
} catch (e: Exception) {
}
super.onStop()
}
@ -310,7 +322,7 @@ class PlayerFragment : Fragment() {
segmentData.segments.forEach { segment: Segment ->
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
if (currentPosition in segmentStart until segmentEnd) {
Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT).show()
@ -383,10 +395,10 @@ class PlayerFragment : Fragment() {
runOnUiThread {
var subtitle = mutableListOf<SubtitleConfiguration>()
if (response.subtitles!!.isNotEmpty()) {
subtitle?.add(
SubtitleConfiguration.Builder(response.subtitles!![0].url!!.toUri())
.setMimeType(response.subtitles!![0].mimeType!!) // The correct MIME type (required).
.setLanguage(response.subtitles!![0].code) // The subtitle language (optional).
subtitle.add(
SubtitleConfiguration.Builder(response.subtitles[0].url!!.toUri())
.setMimeType(response.subtitles[0].mimeType!!) // The correct MIME type (required).
.setLanguage(response.subtitles[0].code) // The subtitle language (optional).
.build()
)
}
@ -426,7 +438,7 @@ class PlayerFragment : Fragment() {
defres != "" -> {
var foundRes = false
run lit@{
response.videoStreams!!.forEachIndexed { index, pipedStream ->
response.videoStreams.forEachIndexed { index, pipedStream ->
if (pipedStream.quality!!.contains(defres)) {
foundRes = true
val dataSourceFactory: DataSource.Factory =
@ -440,13 +452,18 @@ class PlayerFragment : Fragment() {
.createMediaSource(videoItem)
var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[index].quality == "720p" || response.videoStreams[index].quality == "1080p" || response.videoStreams[index].quality == "480p") {
.createMediaSource(
fromUri(response.audioStreams!![0].url!!)
)
if (response.videoStreams[index].quality == "720p" ||
response.videoStreams[index].quality == "1080p" ||
response.videoStreams[index].quality == "480p"
) {
audioSource =
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(
fromUri(
response.audioStreams!![
response.audioStreams[
getMostBitRate(
response.audioStreams
)
@ -490,11 +507,14 @@ class PlayerFragment : Fragment() {
var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[0].quality == "720p" || response.videoStreams[0].quality == "1080p" || response.videoStreams[0].quality == "480p") {
if (response.videoStreams[0].quality == "720p" ||
response.videoStreams[0].quality == "1080p" ||
response.videoStreams[0].quality == "480p"
) {
audioSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(
fromUri(
response.audioStreams!![
response.audioStreams[
getMostBitRate(
response.audioStreams
)
@ -528,13 +548,15 @@ class PlayerFragment : Fragment() {
videosNameArray,
DialogInterface.OnClickListener { _, which ->
whichQuality = which
if (response.subtitles!!.isNotEmpty()) {
if (response.subtitles.isNotEmpty()) {
var subtitle =
mutableListOf<SubtitleConfiguration>()
subtitle?.add(
SubtitleConfiguration.Builder(response.subtitles!![0].url!!.toUri())
.setMimeType(response.subtitles!![0].mimeType!!) // The correct MIME type (required).
.setLanguage(response.subtitles!![0].code) // The subtitle language (optional).
subtitle.add(
SubtitleConfiguration.Builder(
response.subtitles[0].url!!.toUri()
)
.setMimeType(response.subtitles[0].mimeType!!) // The correct MIME type (required).
.setLanguage(response.subtitles[0].code) // The subtitle language (optional).
.build()
)
}
@ -556,13 +578,18 @@ class PlayerFragment : Fragment() {
.createMediaSource(videoItem)
var audioSource: MediaSource =
DefaultMediaSourceFactory(dataSourceFactory)
.createMediaSource(fromUri(response.audioStreams!![0].url!!))
if (response.videoStreams[which - 1].quality == "720p" || response.videoStreams[which - 1].quality == "1080p" || response.videoStreams[which - 1].quality == "480p") {
.createMediaSource(
fromUri(response.audioStreams!![0].url!!)
)
if (response.videoStreams[which - 1].quality == "720p" ||
response.videoStreams[which - 1].quality == "1080p" ||
response.videoStreams[which - 1].quality == "480p"
) {
audioSource =
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(
fromUri(
response.audioStreams!![
response.audioStreams[
getMostBitRate(
response.audioStreams
)
@ -579,14 +606,17 @@ class PlayerFragment : Fragment() {
videosNameArray[which]
}
)
val dialog = builder?.create()
dialog?.show()
val dialog = builder.create()
dialog.show()
}
// 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) {
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 = !(
playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED ||
playbackState == Player.STATE_IDLE ||
playbackState == Player.STATE_ENDED ||
!playWhenReady
)
@ -692,7 +723,8 @@ class PlayerFragment : Fragment() {
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
@ -711,7 +743,7 @@ class PlayerFragment : Fragment() {
vidName.add("No video")
var vidUrl = arrayListOf<String>()
vidUrl.add("")
for (vid in response.videoStreams!!) {
for (vid in response.videoStreams) {
val name = vid.quality + " " + vid.format
vidName.add(name)
vidUrl.add(vid.url!!)
@ -874,10 +906,6 @@ class PlayerFragment : Fragment() {
return index
}
override fun onResume() {
super.onResume()
}
private fun fetchComments() {
lifecycleScope.launchWhenCreated {
val commentsResponse = try {
@ -914,7 +942,7 @@ class PlayerFragment : Fragment() {
return@launchWhenCreated
}
nextPage = response.nextpage
commentsAdapter?.updateItems(response.comments!!)
commentsAdapter?.updateItems(response.comments)
isLoading = false
}
}
@ -950,7 +978,12 @@ class PlayerFragment : Fragment() {
val scrollView = view?.findViewById<ScrollView>(R.id.player_scrollView)
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()
}
}

View File

@ -48,6 +48,7 @@ class PlaylistFragment : Fragment() {
fetchPlaylist(view)
}
private fun fetchPlaylist(view: View) {
fun run() {
lifecycleScope.launchWhenCreated {
@ -66,14 +67,21 @@ class PlaylistFragment : Fragment() {
runOnUiThread {
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_totVideos).text = response.videos.toString() + " Videos"
val sharedPref2 = context?.getSharedPreferences("username", Context.MODE_PRIVATE)
view.findViewById<TextView>(R.id.playlist_totVideos).text =
response.videos.toString() + " Videos"
val sharedPref2 =
context?.getSharedPreferences("username", Context.MODE_PRIVATE)
val user = sharedPref2?.getString("username", "")
var isOwner = false
if (response.uploaderUrl == null && response.uploader.equals(user, 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
val scrollView = view.findViewById<ScrollView>(R.id.playlist_scrollview)
scrollView.viewTreeObserver

View File

@ -1,6 +1,6 @@
package com.github.libretube
import java.util.*
import java.util.LinkedList
import kotlin.reflect.KProperty
class ResettableLazyManager {
@ -25,8 +25,10 @@ interface Resettable {
fun reset()
}
class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: () -> PROPTYPE) : Resettable {
@Volatile var lazyHolder = makeInitBlock()
class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init: () -> PROPTYPE) :
Resettable {
@Volatile
var lazyHolder = makeInitBlock()
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
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)
}

View File

@ -9,13 +9,15 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
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.InputMethodManager
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
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.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
@ -25,11 +27,11 @@ import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.adapters.SearchAdapter
import com.github.libretube.adapters.SearchHistoryAdapter
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.io.IOException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
class SearchFragment : Fragment() {
private val TAG = "SearchFragment"
@ -83,8 +85,7 @@ class SearchFragment : Fragment() {
.setTitle(getString(R.string.choose_filter))
.setSingleChoiceItems(
filterOptions, selectedFilter,
DialogInterface.OnClickListener {
_, id ->
DialogInterface.OnClickListener { _, id ->
tempSelectedItem = id
}
)
@ -154,8 +155,13 @@ class SearchFragment : Fragment() {
GlobalScope.launch {
fetchSuggestions(s.toString(), autoTextView)
delay(1000)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
if (sharedPreferences.getBoolean("search_history_toggle", true)) addtohistory(s.toString())
val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext())
if (sharedPreferences.getBoolean(
"search_history_toggle",
true
)
) addtohistory(s.toString())
fetchSearch(s.toString())
}
}
@ -200,10 +206,12 @@ class SearchFragment : Fragment() {
Log.e(TAG, "HttpException, unexpected response")
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)
}
}
private fun fetchSearch(query: String) {
lifecycleScope.launchWhenCreated {
val response = try {
@ -232,7 +240,11 @@ class SearchFragment : Fragment() {
if (!isLoading) {
isLoading = true
val response = try {
RetrofitInstance.api.getSearchResultsNextPage(query, apiSearchFilter, nextPage!!)
RetrofitInstance.api.getSearchResultsNextPage(
query,
apiSearchFilter,
nextPage!!
)
} catch (e: IOException) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
@ -256,7 +268,7 @@ class SearchFragment : Fragment() {
override fun onResume() {
super.onResume()
requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
requireActivity().window.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN)
}
override fun onStop() {

View File

@ -1,7 +1,11 @@
package com.github.libretube
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.net.Uri
import android.os.Build
@ -24,13 +28,13 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.google.android.material.color.DynamicColors
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.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import org.json.JSONObject
import org.json.JSONTokener
import retrofit2.HttpException
class SettingsActivity :
AppCompatActivity(),
@ -61,7 +65,11 @@ class SettingsActivity :
.registerOnSharedPreferenceChangeListener(this)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, rootKey: String?) {}
override fun onSharedPreferenceChanged(
sharedPreferences: SharedPreferences?,
rootKey: String?
) {
}
class SettingsFragment : PreferenceFragmentCompat() {
val TAG = "Settings"
@ -71,66 +79,72 @@ class SettingsActivity :
}
override fun onCreate(savedInstanceState: Bundle?) {
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
try {
// Open a specific media item using ParcelFileDescriptor.
val resolver: ContentResolver =
requireActivity()
.contentResolver
getContent =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
try {
// Open a specific media item using ParcelFileDescriptor.
val resolver: ContentResolver =
requireActivity()
.contentResolver
// "rw" for read-and-write;
// "rwt" for truncating or overwriting existing file contents.
// val readOnlyMode = "r"
// uri - I have got from onActivityResult
val type = resolver.getType(uri)
// "rw" for read-and-write;
// "rwt" for truncating or overwriting existing file contents.
// val readOnlyMode = "r"
// uri - I have got from onActivityResult
val type = resolver.getType(uri)
var inputStream: InputStream? = resolver.openInputStream(uri)
val channels = ArrayList<String>()
if (type == "application/json") {
val json = inputStream?.bufferedReader()?.readLines()?.get(0)
val jsonObject = JSONTokener(json).nextValue() as JSONObject
Log.e(TAG, jsonObject.getJSONArray("subscriptions").toString())
for (i in 0 until jsonObject.getJSONArray("subscriptions").length()) {
var url = jsonObject.getJSONArray("subscriptions").getJSONObject(i).getString("url")
url = url.replace("https://www.youtube.com/channel/", "")
Log.e(TAG, url)
channels.add(url)
}
} else {
if (type == "application/zip") {
val zis = ZipInputStream(inputStream)
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
if (entry.name.endsWith(".csv")) {
inputStream = zis
break
var inputStream: InputStream? = resolver.openInputStream(uri)
val channels = ArrayList<String>()
if (type == "application/json") {
val json = inputStream?.bufferedReader()?.readLines()?.get(0)
val jsonObject = JSONTokener(json).nextValue() as JSONObject
Log.e(TAG, jsonObject.getJSONArray("subscriptions").toString())
for (
i in 0 until jsonObject.getJSONArray("subscriptions")
.length()
) {
var url =
jsonObject.getJSONArray("subscriptions").getJSONObject(i)
.getString("url")
url = url.replace("https://www.youtube.com/channel/", "")
Log.e(TAG, url)
channels.add(url)
}
} else {
if (type == "application/zip") {
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 {
if (it.isNotBlank()) {
val channelId = it.substringBefore(",")
if (channelId.length == 24)
channels.add(channelId)
inputStream?.bufferedReader()?.readLines()?.forEach {
if (it.isNotBlank()) {
val channelId = it.substringBefore(",")
if (channelId.length == 24)
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)
}
@ -155,7 +169,6 @@ class SettingsActivity :
val login = findPreference<Preference>("login_register")
login?.setOnPreferenceClickListener {
val newFragment = LoginDialog()
newFragment.show(childFragmentManager, "Login")
true
@ -200,7 +213,8 @@ class SettingsActivity :
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
@ -245,7 +259,8 @@ class SettingsActivity :
val clearHistory = findPreference<Preference>("clear_history")
clearHistory?.setOnPreferenceClickListener {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext())
sharedPreferences.edit().remove("search_history").commit()
true
}
@ -269,7 +284,10 @@ class SettingsActivity :
Html.fromHtml(licenseString)
}
MaterialAlertDialogBuilder(view?.context!!)
.setPositiveButton(getString(R.string.okay), DialogInterface.OnClickListener { _, _ -> })
.setPositiveButton(
getString(R.string.okay),
DialogInterface.OnClickListener { _, _ -> }
)
.setMessage(licenseHtml)
.create()
.show()
@ -327,7 +345,8 @@ class SettingsActivity :
fun run() {
lifecycleScope.launchWhenCreated {
val response = try {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
val sharedPref =
context?.getSharedPreferences("token", Context.MODE_PRIVATE)
RetrofitInstance.api.importSubscriptions(
false,
sharedPref?.getString("token", "")!!,
@ -359,5 +378,4 @@ class SettingsActivity :
intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}

View File

@ -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 {
findViewById<View>(R.id.main_container) // TODO move to Attributes

View File

@ -6,6 +6,7 @@ import androidx.preference.SwitchPreferenceCompat
class SponsorBlockSettings : PreferenceFragmentCompat() {
private val TAG = "SponsorBlockDialog"
companion object {
var sponsorBlockEnabled: Boolean = false
var sponsorsEnabled: Boolean = false

View File

@ -9,7 +9,12 @@ import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
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.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
@ -19,9 +24,8 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.github.libretube.adapters.SubscriptionAdapter
import com.github.libretube.adapters.SubscriptionChannelAdapter
import retrofit2.HttpException
import java.io.IOException
import retrofit2.HttpException
class Subscriptions : Fragment() {
val TAG = "SubFragment"
@ -60,7 +64,9 @@ class Subscriptions : Fragment() {
var feedRecView = view.findViewById<RecyclerView>(R.id.sub_feed)
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())
fetchFeed(feedRecView, progressBar, view)
@ -82,7 +88,7 @@ class Subscriptions : Fragment() {
channelRecView.visibility = View.VISIBLE
feedRecView.visibility = View.GONE
//toggle button
// toggle button
val rotate = RotateAnimation(
0F,
180F,
@ -96,12 +102,11 @@ class Subscriptions : Fragment() {
rotate.fillAfter = true
val image = view.findViewById<ImageView>(R.id.toggle)
image.startAnimation(rotate)
} else {
channelRecView.visibility = View.GONE
feedRecView.visibility = View.VISIBLE
//toggle button
// toggle button
val image = view.findViewById<ImageView>(R.id.toggle)
image.clearAnimation()
}
@ -143,7 +148,7 @@ class Subscriptions : Fragment() {
}
if (response.isNotEmpty()) {
subscriptionAdapter = SubscriptionAdapter(response)
feedRecView?.adapter = subscriptionAdapter
feedRecView.adapter = subscriptionAdapter
subscriptionAdapter?.updateItems()
} else {
runOnUiThread {
@ -155,7 +160,8 @@ class Subscriptions : Fragment() {
visibility = View.VISIBLE
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
@ -181,7 +187,7 @@ class Subscriptions : Fragment() {
refreshLayout?.isRefreshing = false
}
if (response.isNotEmpty()) {
channelRecView?.adapter = SubscriptionChannelAdapter(response.toMutableList())
channelRecView.adapter = SubscriptionChannelAdapter(response.toMutableList())
} else {
Toast.makeText(context, R.string.subscribeIsEmpty, Toast.LENGTH_SHORT).show()
}
@ -189,12 +195,14 @@ class Subscriptions : Fragment() {
}
run()
}
override fun onDestroy() {
Log.e(TAG, "Destroyed")
super.onDestroy()
subscriptionAdapter = null
view?.findViewById<RecyclerView>(R.id.sub_feed)?.adapter = null
}
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity

View File

@ -3,10 +3,11 @@ package com.github.libretube
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.PreferenceManager
import java.util.*
import java.util.Locale
fun updateAccentColor(context: Context) {
val colorAccent = PreferenceManager.getDefaultSharedPreferences(context).getString("accent_color", "red")
val colorAccent =
PreferenceManager.getDefaultSharedPreferences(context).getString("accent_color", "red")
when (colorAccent) {
"my" -> context.setTheme(R.style.Theme_MY)
"red" -> context.setTheme(R.style.Theme_Red)
@ -18,7 +19,8 @@ fun updateAccentColor(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) {
"A" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
"L" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

View File

@ -15,10 +15,12 @@ import com.github.libretube.formatShort
import com.github.libretube.obj.StreamItem
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 {
return videoFeed.size
}
fun updateItems(newItems: List<StreamItem>) {
videoFeed.addAll(newItems)
notifyDataSetChanged()
@ -33,8 +35,11 @@ class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) : RecyclerV
override fun onBindViewHolder(holder: ChannelViewHolder, position: Int) {
val trending = videoFeed[position]
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_duration).text = DateUtils.formatElapsedTime(trending.duration!!)
holder.v.findViewById<TextView>(R.id.channel_views).text =
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)
Picasso.get().load(trending.thumbnail).into(thumbnailImage)
holder.v.setOnClickListener {
@ -52,6 +57,7 @@ class ChannelAdapter(private val videoFeed: MutableList<StreamItem>) : RecyclerV
}
}
}
class ChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
init {
}

View File

@ -14,7 +14,8 @@ import com.github.libretube.formatShort
import com.github.libretube.obj.Comment
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>) {
var commentsSize = comments.size
@ -23,16 +24,21 @@ class CommentsAdapter(private val comments: MutableList<Comment>) : RecyclerView
}
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)
}
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_text).text = comments[position].commentText.toString()
holder.v.findViewById<TextView>(R.id.comment_infos).text =
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)
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) {
holder.v.findViewById<ImageView>(R.id.verified_imageView).visibility = View.VISIBLE
}

View File

@ -33,6 +33,7 @@ class PlaylistAdapter(
override fun getItemCount(): Int {
return videoFeed.size
}
fun updateItems(newItems: List<StreamItem>) {
videoFeed.addAll(newItems)
notifyDataSetChanged()
@ -48,7 +49,8 @@ class PlaylistAdapter(
val streamItem = videoFeed[position]
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_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)
Picasso.get().load(streamItem.thumbnail).into(thumbnailImage)
holder.v.setOnClickListener {
@ -68,17 +70,24 @@ class PlaylistAdapter(
val delete = holder.v.findViewById<ImageView>(R.id.delete_playlist)
delete.visibility = View.VISIBLE
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", "")!!
removeFromPlaylist(token, position)
}
}
}
private fun removeFromPlaylist(token: String, position: Int) {
fun run() {
GlobalScope.launch {
val response = try {
RetrofitInstance.api.removeFromPlaylist(token, PlaylistId(playlistId = playlistId, index = position))
RetrofitInstance.api.removeFromPlaylist(
token,
PlaylistId(playlistId = playlistId, index = position)
)
} catch (e: IOException) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
@ -107,6 +116,7 @@ class PlaylistAdapter(
run()
}
}
class PlaylistViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
init {
}

View File

@ -17,10 +17,10 @@ import com.github.libretube.obj.PlaylistId
import com.github.libretube.obj.Playlists
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.squareup.picasso.Picasso
import java.io.IOException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
class PlaylistsAdapter(
private val playlists: MutableList<Playlists>,
@ -30,6 +30,7 @@ class PlaylistsAdapter(
override fun getItemCount(): Int {
return playlists.size
}
fun updateItems(newItems: List<Playlists>) {
playlists.addAll(newItems)
notifyDataSetChanged()
@ -51,7 +52,10 @@ class PlaylistsAdapter(
builder.setTitle(R.string.deletePlaylist)
builder.setMessage(R.string.areYouSure)
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", "")!!
deletePlaylist(playlist.id!!, token, position)
}
@ -66,6 +70,7 @@ class PlaylistsAdapter(
activity.navController.navigate(R.id.playlistFragment, bundle)
}
}
private fun deletePlaylist(id: String, token: String, position: Int) {
fun run() {
GlobalScope.launch {
@ -99,6 +104,7 @@ class PlaylistsAdapter(
run()
}
}
class PlaylistsViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
init {
}

View File

@ -17,7 +17,8 @@ import com.github.libretube.formatShort
import com.github.libretube.obj.SearchItem
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>) {
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) {
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)
Picasso.get().load(item.uploaderAvatar).fit().centerCrop().into(channelImage)
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 viewsString = if (item.views?.toInt() != -1) item.views.formatShort() 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)
channelName.text = item.uploaderName
v.setOnClickListener {
@ -90,13 +97,17 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
activity.navController.navigate(R.id.channel, bundle)
}
}
private fun bindChannel(item: SearchItem) {
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
Picasso.get().load(item.thumbnail).fit().centerCrop().into(channelImage)
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
channelName.text = item.name
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 {
val activity = v.context as MainActivity
val bundle = bundleOf("channel_id" to item.url)
@ -104,6 +115,7 @@ class CustomViewHolder1(private val v: View) : RecyclerView.ViewHolder(v) {
}
// todo sub button
}
private fun bindPlaylist(item: SearchItem) {
val playlistImage = v.findViewById<ImageView>(R.id.search_thumbnail)
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)
playlistChannelName.text = item.uploaderName
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 {
// playlist clicked
val activity = v.context as MainActivity

View File

@ -18,7 +18,8 @@ import com.github.libretube.formatShort
import com.github.libretube.obj.StreamItem
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()
var i = 0
override fun getItemCount(): Int {
@ -42,9 +43,13 @@ class SubscriptionAdapter(private val videoFeed: List<StreamItem>) : RecyclerVie
override fun onBindViewHolder(holder: SubscriptionViewHolder, position: Int) {
val trending = videoFeed[position]
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)
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)
channelImage.setOnClickListener {
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) {
init {
}

View File

@ -12,12 +12,14 @@ import com.github.libretube.R
import com.github.libretube.obj.Subscription
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 {
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 cell = layoutInflater.inflate(R.layout.channel_subscription_row, parent, false)
return SubscriptionChannelViewHolder(cell)
@ -35,6 +37,7 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscrip
}
}
}
class SubscriptionChannelViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
init {
}

View File

@ -18,7 +18,8 @@ import com.github.libretube.formatShort
import com.github.libretube.obj.StreamItem
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 {
return videoFeed.size
}
@ -32,9 +33,13 @@ class TrendingAdapter(private val videoFeed: List<StreamItem>) : RecyclerView.Ad
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val trending = videoFeed[position]
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)
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)
channelImage.setOnClickListener {
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) {
init {
}

View File

@ -1,6 +1,6 @@
package com.github.libretube
import org.junit.Assert.*
import org.junit.Assert.assertEquals
import org.junit.Test
/**