CHANGELOG
made from and to textboxes wider in the cut video screen added search engines in the search view removed filename template override if the user leaves it empty. Now it follows the yt-dlp default fixed app crashing when its tablet added drag handle to scrolling content added pause functionality made video player faster to load for youtube videos
This commit is contained in:
parent
0cacff6e9f
commit
6dc25bab9a
67 changed files with 883 additions and 435 deletions
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
|||
def versionMajor = 1
|
||||
def versionMinor = 6
|
||||
def versionPatch = 3
|
||||
def versionBuild = 9 // bump for dogfood builds, public betas, etc.
|
||||
def versionBuild = 10 // bump for dogfood builds, public betas, etc.
|
||||
def versionExt = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
|
|
|
|||
|
|
@ -185,6 +185,8 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
true
|
||||
}
|
||||
|
||||
(navigationView as NavigationView).getHeaderView(0).findViewById<TextView>(R.id.title).text = ThemeUtil.getStyledAppName(this)
|
||||
}
|
||||
cookieViewModel.updateCookiesFile()
|
||||
val intent = intent
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
|
|
@ -17,6 +18,7 @@ import androidx.recyclerview.widget.ListAdapter
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
|
@ -56,12 +58,13 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.cardView
|
||||
card.tag = "${item!!.id}##card"
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
|
||||
|
||||
// THUMBNAIL ----------------------------------
|
||||
if (!sharedPreferences.getStringSet("hide_thumbnails", emptySet())!!.contains("queue")){
|
||||
val imageURL = item!!.thumb
|
||||
val imageURL = item.thumb
|
||||
if (imageURL.isNotEmpty()) {
|
||||
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
|
||||
} else {
|
||||
|
|
@ -74,7 +77,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
|
||||
// PROGRESS BAR ----------------------------------------------------
|
||||
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
||||
progressBar.tag = "${item!!.id}##progress"
|
||||
progressBar.tag = "${item.id}##progress"
|
||||
progressBar.progress = 0
|
||||
progressBar.isIndeterminate = true
|
||||
|
||||
|
|
@ -105,17 +108,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
val formatDetailsChip = card.findViewById<Chip>(R.id.format_note)
|
||||
val formatDetailsText = StringBuilder(item.format.format_note.uppercase())
|
||||
|
||||
val codecText =
|
||||
if (item.format.encoding != "") {
|
||||
item.format.encoding.uppercase()
|
||||
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
|
||||
item.format.vcodec.uppercase()
|
||||
} else {
|
||||
item.format.acodec.uppercase()
|
||||
}
|
||||
if (codecText != "" && codecText != "none"){
|
||||
formatDetailsText.append(" \t •\t $codecText")
|
||||
}
|
||||
formatDetailsText.append(" \t •\t ${item.container.uppercase().ifEmpty { item.format.container.uppercase() }}")
|
||||
|
||||
val fileSize = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSize != "?") formatDetailsText.append(" \t •\t $fileSize")
|
||||
|
|
@ -131,19 +124,54 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_cancel)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
// PAUSE BUTTON ----------------------------------
|
||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
||||
if (pauseButton.hasOnClickListeners()) pauseButton.setOnClickListener(null)
|
||||
|
||||
cancelButton.setOnClickListener {
|
||||
onItemClickListener.onCancelClick(item.id)
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
cancelButton.setOnClickListener {onItemClickListener.onCancelClick(item.id)}
|
||||
|
||||
if (item.status == DownloadRepository.Status.Paused.toString()){
|
||||
progressBar.isIndeterminate = false
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
||||
pauseButton.tag = ActiveDownloadAction.Resume
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
}else{
|
||||
progressBar.isIndeterminate = true
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
||||
cancelButton.visibility = View.GONE
|
||||
pauseButton.tag = ActiveDownloadAction.Pause
|
||||
}
|
||||
|
||||
pauseButton.setOnClickListener {
|
||||
if (pauseButton.tag == ActiveDownloadAction.Pause){
|
||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Pause)
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
||||
if (progressBar.progress == 0) progressBar.isIndeterminate = false
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
pauseButton.tag = ActiveDownloadAction.Resume
|
||||
}else{
|
||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Resume)
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
||||
progressBar.isIndeterminate = true
|
||||
cancelButton.visibility = View.GONE
|
||||
pauseButton.tag = ActiveDownloadAction.Pause
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
interface OnItemClickListener {
|
||||
fun onCancelClick(itemID: Long)
|
||||
fun onPauseClick(itemID: Long, action: ActiveDownloadAction)
|
||||
fun onOutputClick(item: DownloadItem)
|
||||
}
|
||||
|
||||
enum class ActiveDownloadAction {
|
||||
Resume, Pause
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
|
|
@ -152,7 +180,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.thumb == newItem.thumb
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.thumb == newItem.thumb && oldItem.status == newItem.status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
|
|
@ -17,6 +18,7 @@ import androidx.recyclerview.widget.ListAdapter
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
|
@ -86,9 +88,6 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
|||
}
|
||||
itemTitle.text = title.ifEmpty { item.url }
|
||||
|
||||
val duration = card.findViewById<TextView>(R.id.duration)
|
||||
duration.text = item.duration
|
||||
|
||||
|
||||
val formatDetailsChip = card.findViewById<TextView>(R.id.format_note)
|
||||
val formatDetailsText = StringBuilder(item.format.format_note.uppercase())
|
||||
|
|
@ -110,12 +109,41 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
|||
|
||||
formatDetailsChip.text = formatDetailsText
|
||||
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_cancel)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
// PAUSE BUTTON ----------------------------------
|
||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
||||
if (pauseButton.hasOnClickListeners()) pauseButton.setOnClickListener(null)
|
||||
|
||||
cancelButton.setOnClickListener {
|
||||
onItemClickListener.onCancelClick(item.id)
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
cancelButton.setOnClickListener {onItemClickListener.onCancelClick(item.id)}
|
||||
|
||||
if (item.status == DownloadRepository.Status.Paused.toString()){
|
||||
progressBar.isIndeterminate = false
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
}else{
|
||||
progressBar.isIndeterminate = true
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
||||
cancelButton.visibility = View.GONE
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Pause
|
||||
}
|
||||
|
||||
pauseButton.setOnClickListener {
|
||||
if (pauseButton.tag == ActiveDownloadAdapter.ActiveDownloadAction.Pause){
|
||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Pause)
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
||||
if (progressBar.progress == 0) progressBar.isIndeterminate = false
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
||||
}else{
|
||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Resume)
|
||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
||||
progressBar.isIndeterminate = true
|
||||
cancelButton.visibility = View.GONE
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Pause
|
||||
}
|
||||
}
|
||||
|
||||
card.setOnClickListener {
|
||||
|
|
@ -124,9 +152,11 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
|||
}
|
||||
interface OnItemClickListener {
|
||||
fun onCancelClick(itemID: Long)
|
||||
fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction)
|
||||
fun onCardClick()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
|
|
@ -135,7 +165,7 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
|||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.thumb == newItem.thumb
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.thumb == newItem.thumb && oldItem.status == newItem.status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,13 +90,12 @@ class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity)
|
|||
|
||||
// BUTTONS ----------------------------------
|
||||
val videoURL = video.url
|
||||
val buttonLayout = card.findViewById<LinearLayout>(R.id.download_button_layout)
|
||||
val musicBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_music)
|
||||
val musicBtn = card.findViewById<MaterialButton>(R.id.download_music)
|
||||
musicBtn.tag = "$videoURL##audio"
|
||||
musicBtn.setTag(R.id.cancelDownload, "false")
|
||||
musicBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, DownloadViewModel.Type.audio) }
|
||||
musicBtn.setOnLongClickListener{ onItemClickListener.onLongButtonClick(videoURL, DownloadViewModel.Type.audio); true}
|
||||
val videoBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_video)
|
||||
val videoBtn = card.findViewById<MaterialButton>(R.id.download_video)
|
||||
videoBtn.tag = "$videoURL##video"
|
||||
videoBtn.setTag(R.id.cancelDownload, "false")
|
||||
videoBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, DownloadViewModel.Type.video) }
|
||||
|
|
|
|||
|
|
@ -10,16 +10,16 @@ interface DownloadDao {
|
|||
@Query("SELECT * FROM downloads ORDER BY status")
|
||||
fun getAllDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Active'")
|
||||
@Query("SELECT * FROM downloads WHERE status='Active' or status='Paused'")
|
||||
fun getActiveDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM downloads WHERE status='Active'")
|
||||
@Query("SELECT COUNT(*) FROM downloads WHERE status='Active' or status='Paused'")
|
||||
fun getActiveDownloadsCount() : Flow<Int>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Active'")
|
||||
@Query("SELECT * FROM downloads WHERE status='Active' or status='Paused'")
|
||||
fun getActiveDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Active' or status='Queued'")
|
||||
@Query("SELECT * FROM downloads WHERE status='Active' or status='Queued' or status='Paused'")
|
||||
fun getActiveAndQueuedDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Queued' ORDER BY downloadStartTime, id")
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
val savedDownloads : Flow<List<DownloadItem>> = downloadDao.getSavedDownloads()
|
||||
|
||||
enum class Status {
|
||||
Active, Queued, Error, Processing, Cancelled, Saved
|
||||
Active, Paused, Queued, Error, Cancelled, Saved
|
||||
}
|
||||
|
||||
suspend fun insert(item: DownloadItem) : Long {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anggrayudi.storage.file.dataDirectory
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.repository.CookieRepository
|
||||
|
|
@ -72,11 +73,11 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
|
|||
flush()
|
||||
}
|
||||
|
||||
var dbPath = "/data/data/com.deniscerri.ytdl/app_webview/Cookies"
|
||||
if (!File(dbPath).exists()) dbPath = "/data/data/com.deniscerri.ytdl/app_webview/Default/Cookies"
|
||||
val dbPath = File("/data/data/com.deniscerri.ytdl/").walkTopDown().find { it.name == "Cookies" }
|
||||
?: throw Exception("Cookies File not found!")
|
||||
|
||||
SQLiteDatabase.openDatabase(
|
||||
dbPath, null, OPEN_READONLY
|
||||
dbPath.absolutePath, null, OPEN_READONLY
|
||||
).run {
|
||||
val projection = arrayOf(
|
||||
CookieObject.HOST,
|
||||
|
|
|
|||
|
|
@ -166,6 +166,11 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
else -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())
|
||||
}
|
||||
|
||||
val container = when(type){
|
||||
Type.audio -> sharedPreferences.getString("audio_format", "")
|
||||
else -> sharedPreferences.getString("video_format", "")
|
||||
}
|
||||
|
||||
|
||||
val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
|
||||
|
|
@ -182,10 +187,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
resultItem.duration,
|
||||
type,
|
||||
getFormat(resultItem.formats, type),
|
||||
sharedPreferences.getString("video_format", "Default")!!,
|
||||
container!!,
|
||||
"",
|
||||
resultItem.formats,
|
||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0, null
|
||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -307,7 +312,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
container,
|
||||
"",
|
||||
ArrayList(),
|
||||
path, historyItem.website, "", "", audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0, null
|
||||
path, historyItem.website, "", "", audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -459,7 +464,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
var exists = false
|
||||
|
||||
items.forEach {
|
||||
it.status = DownloadRepository.Status.Queued.toString()
|
||||
if (it.status != DownloadRepository.Status.Paused.toString()) it.status = DownloadRepository.Status.Queued.toString()
|
||||
if (activeAndQueuedDownloads.firstOrNull{d ->
|
||||
d.id = 0
|
||||
d.status = DownloadRepository.Status.Queued.toString()
|
||||
|
|
|
|||
|
|
@ -3,8 +3,14 @@ package com.deniscerri.ytdlnis.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(c: Context, intent: Intent) {
|
||||
|
|
@ -14,6 +20,14 @@ class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
|||
val notificationUtil = NotificationUtil(c)
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
|
||||
val dbManager = DBManager.getInstance(c)
|
||||
CoroutineScope(Dispatchers.IO).launch{
|
||||
val item = dbManager.downloadDao.getDownloadById(id.toLong())
|
||||
item.status = DownloadRepository.Status.Cancelled.toString()
|
||||
dbManager.downloadDao.update(item)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,12 @@ import android.app.Activity
|
|||
import android.content.*
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources.Theme
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.view.View.*
|
||||
import android.widget.*
|
||||
|
|
@ -36,7 +34,6 @@ import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
|||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.ResultCardDetailsDialog
|
||||
|
|
@ -137,7 +134,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
searchHistory = view.findViewById(R.id.search_history_scroll_view)
|
||||
searchHistoryLinearLayout = view.findViewById(R.id.search_history_linear_layout)
|
||||
|
||||
materialToolbar!!.title = ThemeUtil.getStyledAppName(requireContext())
|
||||
runCatching { materialToolbar!!.title = ThemeUtil.getStyledAppName(requireContext()) }
|
||||
|
||||
homeAdapter =
|
||||
HomeAdapter(
|
||||
|
|
@ -257,6 +254,30 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
val queriesInitStartBtn = queriesConstraint.findViewById<MaterialButton>(R.id.init_search_query)
|
||||
val isRightToLeft = resources.getBoolean(R.bool.is_right_to_left)
|
||||
|
||||
val providersChipGroup = searchView!!.findViewById<ChipGroup>(R.id.providers)
|
||||
val providers = resources.getStringArray(R.array.search_engines)
|
||||
val providersValues = resources.getStringArray(R.array.search_engines_values).toMutableList()
|
||||
val currentProvider = sharedPreferences?.getString("search_engine", "ytsearch")
|
||||
|
||||
for(i in providersValues.indices){
|
||||
val provider = providers[i]
|
||||
val providerValue = providersValues[i]
|
||||
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, providersChipGroup, false) as Chip
|
||||
tmp.text = provider
|
||||
tmp.id = i
|
||||
|
||||
if (currentProvider == providerValue) tmp.isChecked = true
|
||||
|
||||
tmp.setOnClickListener {
|
||||
val editor = sharedPreferences?.edit()
|
||||
editor?.putString("search_engine", providerValue)
|
||||
editor?.apply()
|
||||
|
||||
}
|
||||
|
||||
providersChipGroup!!.addView(tmp)
|
||||
}
|
||||
|
||||
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
searchView!!.addTransitionListener { _, _, newState ->
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.map
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.MergingMediaSource
|
||||
|
|
@ -35,6 +34,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadMinifiedAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
|
@ -68,7 +68,6 @@ import java.util.*
|
|||
class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogFragment(), GenericDownloadAdapter.OnItemClickListener, ActiveDownloadMinifiedAdapter.OnItemClickListener {
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var player: ExoPlayer
|
||||
private lateinit var videoView: PlayerView
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
|
|
@ -232,9 +231,8 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
}
|
||||
|
||||
|
||||
videoView = view.findViewById<PlayerView>(R.id.video_view)
|
||||
videoView = view.findViewById(R.id.video_view)
|
||||
val pause = view.findViewById<MaterialButton>(R.id.pause)
|
||||
val frameLayout = view.findViewById<FrameLayout>(R.id.frame_layout)
|
||||
|
||||
val player = VideoPlayerUtil.buildPlayer(requireContext())
|
||||
videoView.player = player
|
||||
|
|
@ -261,7 +259,7 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
}
|
||||
}
|
||||
|
||||
data.removeFirst()
|
||||
if (data.size > 1) data.removeFirst()
|
||||
|
||||
if (data.isEmpty()) throw Exception("No Streaming URL found!")
|
||||
if (data.size == 2){
|
||||
|
|
@ -280,7 +278,6 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
player.prepare()
|
||||
player.play()
|
||||
}catch (e: Exception){
|
||||
frameLayout.visibility = View.GONE
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
|
@ -536,7 +533,24 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
override fun onCancelClick(itemID: Long) {
|
||||
cancelActiveDownload(itemID)
|
||||
}
|
||||
override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction) {
|
||||
val item = activeItems.find { it.id == itemID } ?: return
|
||||
when(action){
|
||||
ActiveDownloadAdapter.ActiveDownloadAction.Pause -> {
|
||||
cancelItem(itemID.toInt())
|
||||
item.status = DownloadRepository.Status.Paused.toString()
|
||||
downloadViewModel.updateDownload(item)
|
||||
}
|
||||
ActiveDownloadAdapter.ActiveDownloadAction.Resume -> {
|
||||
item.status = DownloadRepository.Status.Active.toString()
|
||||
downloadViewModel.updateDownload(item)
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
override fun onCardClick() {
|
||||
this.dismiss()
|
||||
findNavController().navigate(
|
||||
|
|
@ -544,6 +558,12 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
)
|
||||
}
|
||||
|
||||
private fun cancelItem(id: Int){
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
private fun cancelActiveDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.view.View
|
|||
import android.view.View.OnClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
|
@ -19,8 +20,11 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
||||
class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
|
|
@ -32,6 +36,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
lateinit var downloadItem: DownloadItem
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var list: List<DownloadItem>
|
||||
private lateinit var pauseResume: MaterialButton
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -39,7 +44,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_active, container, false)
|
||||
activity = getActivity()
|
||||
notificationUtil = NotificationUtil(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
|
|
@ -59,10 +64,62 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
activeRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
activeRecyclerView.adapter = activeDownloads
|
||||
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
||||
pauseResume = view.findViewById(R.id.pause_resume)
|
||||
|
||||
pauseResume.setOnClickListener {
|
||||
if (pauseResume.text == requireContext().getString(R.string.pause)){
|
||||
list.forEach {
|
||||
cancelItem(it.id.toInt())
|
||||
it.status = DownloadRepository.Status.Paused.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
|
||||
val card = view.findViewWithTag<MaterialCardView>("${it.id}##card")
|
||||
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
||||
|
||||
progressBar.isIndeterminate = false
|
||||
pauseButton.icon = ContextCompat.getDrawable(requireContext(), R.drawable.exomedia_ic_play_arrow_white)
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
}
|
||||
}else{
|
||||
val toQueue = list.filter { it.status == DownloadRepository.Status.Paused.toString() }
|
||||
toQueue.forEach {
|
||||
it.status = DownloadRepository.Status.Active.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
|
||||
val card = view.findViewWithTag<MaterialCardView>("${it.id}##card")
|
||||
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
||||
|
||||
pauseButton.icon = ContextCompat.getDrawable(requireContext(), R.drawable.exomedia_ic_pause_white)
|
||||
progressBar.isIndeterminate = true
|
||||
cancelButton.visibility = View.GONE
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Pause
|
||||
}
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(toQueue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadViewModel.activeDownloads.observe(viewLifecycleOwner) {
|
||||
list = it
|
||||
activeDownloads.submitList(it)
|
||||
|
||||
if (list.isNotEmpty()){
|
||||
pauseResume.visibility = View.VISIBLE
|
||||
if (list.all { l -> l.status == DownloadRepository.Status.Paused.toString() }){
|
||||
pauseResume.text = requireContext().getString(R.string.resume)
|
||||
}else{
|
||||
pauseResume.text = requireContext().getString(R.string.pause)
|
||||
}
|
||||
}else{
|
||||
pauseResume.visibility = View.GONE
|
||||
}
|
||||
|
||||
it.forEach{item ->
|
||||
WorkManager.getInstance(requireContext())
|
||||
.getWorkInfosForUniqueWorkLiveData(item.id.toString())
|
||||
|
|
@ -95,6 +152,25 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction) {
|
||||
val item = list.find { it.id == itemID } ?: return
|
||||
when(action){
|
||||
ActiveDownloadAdapter.ActiveDownloadAction.Pause -> {
|
||||
cancelItem(itemID.toInt())
|
||||
item.status = DownloadRepository.Status.Paused.toString()
|
||||
downloadViewModel.updateDownload(item)
|
||||
}
|
||||
ActiveDownloadAdapter.ActiveDownloadAction.Resume -> {
|
||||
item.status = DownloadRepository.Status.Active.toString()
|
||||
downloadViewModel.updateDownload(item)
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onOutputClick(item: DownloadItem) {
|
||||
if (item.logID != null) {
|
||||
val bundle = Bundle()
|
||||
|
|
@ -106,12 +182,14 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
}
|
||||
}
|
||||
|
||||
private fun cancelDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
private fun cancelItem(id: Int){
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
private fun cancelDownload(itemID: Long){
|
||||
cancelItem(itemID.toInt())
|
||||
list.find { it.id == itemID }?.let {
|
||||
it.status = DownloadRepository.Status.Cancelled.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ class DownloadQueueMainFragment : Fragment(){
|
|||
when(m.itemId){
|
||||
R.id.clear_queue -> {
|
||||
showDeleteDialog {
|
||||
cancelAllDownloads()
|
||||
downloadViewModel.cancelQueued()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ package com.deniscerri.ytdlnis.ui.more.settings
|
|||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
|
|
@ -18,10 +16,8 @@ import androidx.work.WorkInfo
|
|||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.ui.more.TerminalActivity
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.gms.common.wrappers.Wrappers.packageManager
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
|
|
@ -33,7 +29,7 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
private var accent: ListPreference? = null
|
||||
private var highContrast: SwitchPreferenceCompat? = null
|
||||
private var locale: ListPreference? = null
|
||||
private var hideTerminal: SwitchPreferenceCompat? = null
|
||||
private var showTerminalShareIcon: SwitchPreferenceCompat? = null
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
|
@ -54,7 +50,7 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
accent = findPreference("theme_accent")
|
||||
highContrast = findPreference("high_contrast")
|
||||
locale = findPreference("locale")
|
||||
hideTerminal = findPreference("hide_terminal")
|
||||
showTerminalShareIcon = findPreference("show_terminal")
|
||||
|
||||
if(VERSION.SDK_INT < VERSION_CODES.TIRAMISU){
|
||||
val values = resources.getStringArray(R.array.language_values)
|
||||
|
|
@ -115,7 +111,7 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
true
|
||||
}
|
||||
|
||||
hideTerminal!!.onPreferenceChangeListener =
|
||||
showTerminalShareIcon!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { pref: Preference?, _: Any ->
|
||||
val packageManager = requireContext().packageManager
|
||||
val aliasComponentName = ComponentName(requireContext(), "com.deniscerri.ytdlnis.terminalShareAlias")
|
||||
|
|
|
|||
|
|
@ -2,9 +2,15 @@ package com.deniscerri.ytdlnis.util
|
|||
|
||||
import android.content.Context
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.storage.StorageManager
|
||||
import android.os.storage.StorageVolume
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.anggrayudi.storage.callback.FileCallback
|
||||
|
|
@ -12,11 +18,12 @@ import com.anggrayudi.storage.callback.FolderCallback
|
|||
import com.anggrayudi.storage.file.copyFileTo
|
||||
import com.anggrayudi.storage.file.copyFolderTo
|
||||
import com.anggrayudi.storage.file.getAbsolutePath
|
||||
import com.anggrayudi.storage.file.moveFileTo
|
||||
import com.anggrayudi.storage.file.moveFolderTo
|
||||
import com.anggrayudi.storage.file.getBasePath
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.internal.closeQuietly
|
||||
import java.io.File
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
|
@ -32,15 +39,10 @@ import kotlin.math.pow
|
|||
object FileUtil {
|
||||
|
||||
fun deleteFile(path: String){
|
||||
val file = File(path)
|
||||
if (file.exists()) {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
|
||||
internal object Compare {
|
||||
fun max(a: File, b: File): File {
|
||||
return if (a.length() > b.length()) a else b
|
||||
runCatching {
|
||||
if (!File(path).delete()){
|
||||
DocumentFile.fromSingleUri(App.instance, Uri.parse(path))?.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +102,7 @@ object FileUtil {
|
|||
withContext(Dispatchers.IO){
|
||||
curr.copyFolderTo(context, dst!!, skipEmptyFiles = false, callback = object : FolderCallback() {
|
||||
override fun onStart(folder: DocumentFile, totalFilesToCopy: Int, workerThread: Thread): Long {
|
||||
return 1000 // update progress every 1 second
|
||||
return 500 // update progress every half second
|
||||
}
|
||||
|
||||
override fun onParentConflict(destinationFolder: DocumentFile, action: ParentFolderConflictAction, canMerge: Boolean) {
|
||||
|
|
@ -120,11 +122,66 @@ object FileUtil {
|
|||
it.deleteRecursively()
|
||||
}
|
||||
|
||||
override fun onFailed(errorCode: ErrorCode) {
|
||||
//if its usb?
|
||||
runCatching {
|
||||
it.walkTopDown().forEach { f ->
|
||||
if (f.isDirectory) return@forEach
|
||||
|
||||
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(f.extension) ?: "*/*"
|
||||
|
||||
val destUri = DocumentsContract.createDocument(
|
||||
context.contentResolver,
|
||||
dst.uri,
|
||||
mimeType,
|
||||
f.name
|
||||
) ?: return@runCatching
|
||||
|
||||
val inputStream = f.inputStream()
|
||||
val outputStream =
|
||||
context.contentResolver.openOutputStream(destUri) ?: return@runCatching
|
||||
inputStream.copyTo(outputStream)
|
||||
inputStream.closeQuietly()
|
||||
outputStream.closeQuietly()
|
||||
|
||||
fileList.add(DocumentFile.fromSingleUri(context, destUri)!!.getAbsolutePath(context))
|
||||
}
|
||||
|
||||
it.deleteRecursively()
|
||||
}
|
||||
super.onFailed(errorCode)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}else{
|
||||
withContext(Dispatchers.IO){
|
||||
curr.copyFileTo(context, dst!!, callback = object : FileCallback() {
|
||||
override fun onFailed(errorCode: ErrorCode) {
|
||||
//if its usb?
|
||||
runCatching {
|
||||
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
||||
|
||||
val destUri = DocumentsContract.createDocument(
|
||||
context.contentResolver,
|
||||
dst.uri,
|
||||
mimeType,
|
||||
it.name
|
||||
) ?: return@runCatching
|
||||
|
||||
val inputStream = it.inputStream()
|
||||
val outputStream =
|
||||
context.contentResolver.openOutputStream(destUri) ?: return@runCatching
|
||||
inputStream.copyTo(outputStream)
|
||||
inputStream.closeQuietly()
|
||||
outputStream.closeQuietly()
|
||||
|
||||
fileList.add(DocumentFile.fromSingleUri(context, destUri)!!.getAbsolutePath(context))
|
||||
it.delete()
|
||||
}
|
||||
super.onFailed(errorCode)
|
||||
}
|
||||
|
||||
override fun onStart(file: Any, workerThread: Thread): Long {
|
||||
return 1000 // update progress every 1 second
|
||||
}
|
||||
|
|
@ -136,7 +193,7 @@ object FileUtil {
|
|||
override fun onCompleted(result: Any) {
|
||||
destFile = (result as DocumentFile)
|
||||
fileList.add(destFile.getAbsolutePath(context))
|
||||
it.deleteRecursively()
|
||||
it.delete()
|
||||
super.onCompleted(result)
|
||||
}
|
||||
})
|
||||
|
|
@ -170,10 +227,9 @@ object FileUtil {
|
|||
}
|
||||
}
|
||||
private fun scanMedia(files: List<String>, context: Context) : List<String> {
|
||||
|
||||
try {
|
||||
val paths = files.sortedByDescending { File(it).length() }
|
||||
MediaScannerConnection.scanFile(context, paths.toTypedArray(), null, null)
|
||||
runCatching {MediaScannerConnection.scanFile(context, paths.toTypedArray(), null, null) }
|
||||
return paths
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.util.Log
|
|||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.Converters
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
|
|
@ -452,12 +453,12 @@ class InfoUtil(private val context: Context) {
|
|||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
if (cookiesFile.exists()) {
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
val proxy = sharedPreferences.getString("proxy", "")
|
||||
if (proxy!!.isNotBlank()){
|
||||
if (proxy!!.isNotBlank()) {
|
||||
request.addOption("--proxy", proxy)
|
||||
}
|
||||
|
||||
|
|
@ -471,34 +472,7 @@ class InfoUtil(private val context: Context) {
|
|||
val json = results[0]
|
||||
val jsonArray = JSONArray(json)
|
||||
|
||||
val formats : ArrayList<Format> = ArrayList()
|
||||
for (f in 0 until jsonArray.length()){
|
||||
val format = jsonArray.getJSONObject(f)
|
||||
if (format.has("filesize")){
|
||||
if (format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
try{
|
||||
val size = format.get("filesize").toString().toFloat()
|
||||
format.remove("filesize")
|
||||
format.put("filesize", size)
|
||||
}catch (ignored: Exception){}
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (format.has("format_note")){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
if (formatProper!!.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
|
||||
return formats
|
||||
return parseYTDLFormats(jsonArray)
|
||||
} catch (e: Exception) {
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
|
|
@ -540,35 +514,8 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
YoutubeDL.getInstance().execute(request){ progress, _, line ->
|
||||
try{
|
||||
val formats = mutableListOf<Format>()
|
||||
val listOfStrings = JSONArray(line)
|
||||
for (f in 0 until listOfStrings.length()){
|
||||
val format = listOfStrings.get(f) as JSONObject
|
||||
try{
|
||||
if (format.getString("filesize") == "None") continue
|
||||
}catch (e: Exception) { continue }
|
||||
if (format.has("filesize")){
|
||||
if (format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
try{
|
||||
val size = format.get("filesize").toString().toFloat()
|
||||
format.remove("filesize")
|
||||
format.put("filesize", size)
|
||||
}catch (ignored: Exception){}
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if ( !formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
if (formatProper.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
progress(formats)
|
||||
progress(parseYTDLFormats(listOfStrings))
|
||||
}catch (e: Exception){
|
||||
progress(emptyList())
|
||||
}
|
||||
|
|
@ -668,37 +615,7 @@ class InfoUtil(private val context: Context) {
|
|||
if (jsonObject.has("playlist_title")) playlistTitle = jsonObject.getString("playlist_title")
|
||||
if(playlistTitle.equals(query)) playlistTitle = ""
|
||||
val formatsInJSON = if (jsonObject.has("formats") && jsonObject.get("formats") is JSONArray) jsonObject.getJSONArray("formats") else null
|
||||
val formats : ArrayList<Format> = ArrayList()
|
||||
if (formatsInJSON != null) {
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.has("filesize")){
|
||||
if (format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
try{
|
||||
val size = format.get("filesize").toString().toFloat()
|
||||
format.remove("filesize")
|
||||
format.put("filesize", size)
|
||||
}catch (ignored: Exception){}
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.format_note == null) continue
|
||||
if (format.has("format_note")){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
if (!formatProper.format_note.endsWith("audio", true)){
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
}
|
||||
if (formatProper.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
}
|
||||
val formats : ArrayList<Format> = parseYTDLFormats(formatsInJSON)
|
||||
|
||||
val chaptersInJSON = if (jsonObject.has("chapters") && jsonObject.get("chapters") is JSONArray) jsonObject.getJSONArray("chapters") else null
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
|
|
@ -734,6 +651,47 @@ class InfoUtil(private val context: Context) {
|
|||
return items
|
||||
}
|
||||
|
||||
private fun parseYTDLFormats(formatsInJSON: JSONArray?) : ArrayList<Format> {
|
||||
val formats = arrayListOf<Format>()
|
||||
|
||||
if (formatsInJSON != null) {
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.has("filesize")){
|
||||
if (format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
if (format.has("filesize_approx") && format.get("filesize_approx") != "None"){
|
||||
format.put("filesize", format.getInt("filesize_approx"))
|
||||
}else{
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
}
|
||||
try{
|
||||
val size = format.get("filesize").toString().toFloat()
|
||||
format.remove("filesize")
|
||||
format.put("filesize", size)
|
||||
}catch (ignored: Exception){}
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.format_note == null) continue
|
||||
if (format.has("format_note")){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
if (!formatProper.format_note.endsWith("audio", true)){
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
}
|
||||
if (formatProper.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
}
|
||||
|
||||
return formats
|
||||
}
|
||||
|
||||
fun getMissingInfo(url: String): ResultItem? {
|
||||
try {
|
||||
val request = YoutubeDLRequest(url)
|
||||
|
|
@ -885,33 +843,57 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
fun getStreamingUrlAndChapters(url: String) : MutableList<String?> {
|
||||
try {
|
||||
val request = YoutubeDLRequest(url)
|
||||
request.addOption("--get-url")
|
||||
request.addOption("--print", "%(chapters)s")
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val p = Pattern.compile("(^(https?)://(www.)?(music.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)")
|
||||
val m = p.matcher(url)
|
||||
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
if (m.find()){
|
||||
return getStreamingUrlAndChaptersFromPIPED(getIDFromYoutubeURL(url))
|
||||
}else{
|
||||
throw Exception()
|
||||
}
|
||||
}catch (e: Exception) {
|
||||
try {
|
||||
val request = YoutubeDLRequest(url)
|
||||
request.addOption("--get-url")
|
||||
request.addOption("--print", "%(chapters)s")
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
|
||||
val proxy = sharedPreferences.getString("proxy", "")
|
||||
if (proxy!!.isNotBlank()){
|
||||
request.addOption("--proxy", proxy)
|
||||
}
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: Array<String?> = try {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
youtubeDLResponse.out.split(lineSeparator!!).toTypedArray()
|
||||
val proxy = sharedPreferences.getString("proxy", "")
|
||||
if (proxy!!.isNotBlank()){
|
||||
request.addOption("--proxy", proxy)
|
||||
}
|
||||
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: Array<String?> = try {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
youtubeDLResponse.out.split(lineSeparator!!).toTypedArray()
|
||||
} catch (e: Exception) {
|
||||
arrayOf(youtubeDLResponse.out)
|
||||
}
|
||||
return results.filter { it!!.isNotEmpty() }.toMutableList()
|
||||
} catch (e: Exception) {
|
||||
arrayOf(youtubeDLResponse.out)
|
||||
return mutableListOf()
|
||||
}
|
||||
return results.filter { it!!.isNotEmpty() }.toMutableList()
|
||||
} catch (e: Exception) {
|
||||
return mutableListOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStreamingUrlAndChaptersFromPIPED(id: String) : MutableList<String?> {
|
||||
val res = genericRequest("$pipedURL/streams/$id")
|
||||
if (res.length() == 0) {
|
||||
throw Exception()
|
||||
}else{
|
||||
val item = createVideoFromPipedJSON(res, id)
|
||||
if (item!!.urls.isBlank()) throw Exception()
|
||||
val list = mutableListOf<String?>(Gson().toJson(item.chapters))
|
||||
list.addAll(item.urls.split(","))
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -978,7 +960,6 @@ class InfoUtil(private val context: Context) {
|
|||
request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author.take(25)))
|
||||
}
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic$",""))
|
||||
if (downloadItem.customFileNameTemplate.isBlank()) downloadItem.customFileNameTemplate = "%(uploader|${downloadItem.author})s - %(title)s"
|
||||
downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.replace("%(uploader)s", "%(uploader|${downloadItem.author})s")
|
||||
|
||||
if (downloadItem.downloadSections.isNotBlank()){
|
||||
|
|
@ -1050,38 +1031,41 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
request.addOption("--embed-metadata")
|
||||
|
||||
if (downloadItem.audioPreferences.embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "jpg")
|
||||
if (sharedPreferences.getBoolean("crop_thumbnail", true)){
|
||||
try {
|
||||
val config = File(context.cacheDir.absolutePath + "/downloads/${downloadItem.id}/config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt")
|
||||
val configData = "--ppa \"ffmpeg: -c:v mjpeg -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\""
|
||||
config.writeText(configData)
|
||||
request.addOption("--ppa", "ThumbnailsConvertor:-qmin 1 -q:v 1")
|
||||
request.addOption("--config", config.absolutePath)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s")
|
||||
|
||||
if (downloadItem.playlistTitle.isNotEmpty()) {
|
||||
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
||||
request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s")
|
||||
} else {
|
||||
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
|
||||
}
|
||||
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
|
||||
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||
request.addOption("--split-chapters")
|
||||
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
||||
}else{
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
request.addOption("--embed-metadata")
|
||||
|
||||
if (downloadItem.audioPreferences.embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "jpg")
|
||||
if (sharedPreferences.getBoolean("crop_thumbnail", true)){
|
||||
try {
|
||||
val config = File(context.cacheDir.absolutePath + "/downloads/${downloadItem.id}/config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt")
|
||||
val configData = "--ppa \"ffmpeg: -c:v mjpeg -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\""
|
||||
config.writeText(configData)
|
||||
request.addOption("--ppa", "ThumbnailsConvertor:-qmin 1 -q:v 1")
|
||||
request.addOption("--config", config.absolutePath)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s")
|
||||
|
||||
if (downloadItem.playlistTitle.isNotEmpty()) {
|
||||
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
||||
request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s")
|
||||
} else {
|
||||
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
|
||||
}
|
||||
|
||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1149,7 +1133,9 @@ class InfoUtil(private val context: Context) {
|
|||
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||
request.addOption("--split-chapters")
|
||||
}else{
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ object ThemeUtil {
|
|||
private fun getThemeColor(context: Context, colorCode: Int): Int {
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val accent = sharedPreferences.getString("theme_accent", "blue")
|
||||
return if (accent == "Default" || accent == "blue"){
|
||||
"c22727".toInt(16)
|
||||
return if (accent == "blue"){
|
||||
"d43c3b".toInt(16)
|
||||
}else{
|
||||
val value = TypedValue()
|
||||
context.theme.resolveAttribute(colorCode, value, true)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
|
|
@ -251,7 +252,7 @@ object UiUtil {
|
|||
fragmentContext.packageName + ".fileprovider",
|
||||
file
|
||||
)
|
||||
val mime = fragmentContext.contentResolver.getType(uri)
|
||||
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.extension)
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.setDataAndType(uri, mime)
|
||||
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class DownloadWorker(
|
|||
return Result.failure()
|
||||
}
|
||||
|
||||
if (downloadItem.status != DownloadRepository.Status.Queued.toString()) return Result.failure()
|
||||
if (downloadItem.status != DownloadRepository.Status.Queued.toString() && downloadItem.status != DownloadRepository.Status.Paused.toString()) return Result.failure()
|
||||
|
||||
val pendingIntent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
|
|
@ -134,7 +134,7 @@ class DownloadWorker(
|
|||
}.onSuccess {
|
||||
val wasQuickDownloaded = updateDownloadItem(downloadItem, infoUtil, dao, resultDao)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
runBlocking {
|
||||
var finalPaths : List<String>?
|
||||
//move file from internal to set download directory
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
|
|
@ -174,30 +174,26 @@ class DownloadWorker(
|
|||
downloadItem.title, if (finalPaths?.first().equals(context.getString(R.string.unfound_file))) null else finalPaths,
|
||||
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
||||
)
|
||||
}
|
||||
|
||||
if (wasQuickDownloaded){
|
||||
runCatching {
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false))
|
||||
runBlocking {
|
||||
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
|
||||
if (res != null) {
|
||||
resultDao.insert(res)
|
||||
if (wasQuickDownloaded){
|
||||
runCatching {
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false))
|
||||
runBlocking {
|
||||
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
|
||||
if (res != null) {
|
||||
resultDao.insert(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
dao.delete(downloadItem.id)
|
||||
}
|
||||
|
||||
|
||||
}.onFailure {
|
||||
if (it is YoutubeDL.CanceledException) {
|
||||
downloadItem.status = DownloadRepository.Status.Cancelled.toString()
|
||||
runBlocking {
|
||||
dao.update(downloadItem)
|
||||
}
|
||||
return Result.failure(
|
||||
Data.Builder().putString("output", "Download has been cancelled!").build()
|
||||
)
|
||||
|
|
|
|||
5
app/src/main/res/drawable/ic_refresh_white.xml
Normal file
5
app/src/main/res/drawable/ic_refresh_white.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:textColorPrimary" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/line.xml
Normal file
12
app/src/main/res/drawable/line.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="@android:color/transparent" />
|
||||
|
||||
<padding
|
||||
android:top="10dp"
|
||||
android:left="10dp"
|
||||
android:right="10dp"
|
||||
android:bottom="10dp"/>
|
||||
</shape>
|
||||
9
app/src/main/res/drawable/line_drawable.xml
Normal file
9
app/src/main/res/drawable/line_drawable.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_pressed="true"
|
||||
android:drawable="@drawable/line"/>
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/line"/>
|
||||
</selector>
|
||||
18
app/src/main/res/drawable/thumb.xml
Normal file
18
app/src/main/res/drawable/thumb.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:pivotX="65%"
|
||||
android:pivotY="20%"
|
||||
android:toDegrees="250"
|
||||
android:fromDegrees="270">
|
||||
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?android:colorAccent"/>
|
||||
<size
|
||||
android:width="40dp"
|
||||
android:height="20dp"/>
|
||||
<corners
|
||||
android:topLeftRadius="20dp"
|
||||
android:topRightRadius="20dp"/>
|
||||
</shape>
|
||||
|
||||
</rotate>
|
||||
8
app/src/main/res/drawable/thumb_drawable.xml
Normal file
8
app/src/main/res/drawable/thumb_drawable.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_pressed="true"
|
||||
android:drawable="@drawable/thumb"/>
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/thumb"/>
|
||||
</selector>
|
||||
|
|
@ -27,6 +27,28 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:singleSelection="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -132,9 +154,12 @@
|
|||
android:id="@+id/recyclerViewHome"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="100dp"
|
||||
app:spanCount="3"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,28 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:singleSelection="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -147,9 +169,13 @@
|
|||
android:id="@+id/recyclerViewHome"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="100dp"
|
||||
app:spanCount="2"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,28 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -132,9 +154,12 @@
|
|||
android:id="@+id/recyclerViewHome"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="100dp"
|
||||
app:spanCount="4"
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@
|
|||
android:dividerPadding="5dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||
app:layout_constraintEnd_toStartOf="@+id/active_download_cancel"
|
||||
app:layout_constraintEnd_toStartOf="@+id/active_download_pause"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearlayout2_horizontalscrollview">
|
||||
|
|
@ -152,14 +152,30 @@
|
|||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/active_download_cancel"
|
||||
android:id="@+id/active_download_pause"
|
||||
style="?attr/materialIconButtonFilledStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:cornerRadius="15dp"
|
||||
app:icon="@drawable/ic_cancel"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:icon="@drawable/exomedia_ic_play_arrow_white"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:textColorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||
app:layout_constraintEnd_toStartOf="@id/active_download_delete"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearlayout2_horizontalscrollview"
|
||||
app:layout_constraintVertical_bias="0.51" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/active_download_delete"
|
||||
style="?attr/materialIconButtonFilledStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:cornerRadius="15dp"
|
||||
app:icon="@drawable/baseline_delete_24"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:textColorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||
|
|
|
|||
|
|
@ -15,63 +15,53 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
|
||||
app:strokeWidth="0dp"
|
||||
app:cardElevation="10dp"
|
||||
app:cardMaxElevation="12dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom"
|
||||
android:alpha="0.3"
|
||||
android:scaleY="200"
|
||||
app:trackColor="#000" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image_view"
|
||||
<FrameLayout
|
||||
android:id="@+id/image_frame"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="?attr/colorSurfaceVariant"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="H,16:9"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
||||
app:layout_constraintHorizontal_weight="0.3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar" />
|
||||
app:layout_constraintDimensionRatio="H,16:9"
|
||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
|
||||
android:adjustViewBounds="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:elevation="10dp"
|
||||
app:layout_constraintStart_toStartOf="@id/image_view"
|
||||
app:layout_constraintEnd_toEndOf="@id/image_view"
|
||||
app:layout_constraintBottom_toBottomOf="@id/image_view"
|
||||
app:layout_constraintTop_toTopOf="@id/image_view"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:alpha="0.6"
|
||||
android:scaleY="200"
|
||||
app:trackColor="#000" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:background="#80000000"
|
||||
android:clickable="false"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLength="17"
|
||||
android:maxLines="1"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/image_view"
|
||||
app:layout_constraintEnd_toEndOf="@+id/image_view" />
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:background="?attr/colorSurfaceVariant"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/download_item_data"
|
||||
|
|
@ -79,9 +69,9 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/active_download_cancel"
|
||||
app:layout_constraintEnd_toStartOf="@id/active_download_pause"
|
||||
app:layout_constraintHorizontal_weight="0.7"
|
||||
app:layout_constraintStart_toEndOf="@+id/image_view"
|
||||
app:layout_constraintStart_toEndOf="@+id/image_frame"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
|
|
@ -139,14 +129,29 @@
|
|||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/active_download_cancel"
|
||||
style="?attr/materialIconButtonFilledStyle"
|
||||
android:id="@+id/active_download_pause"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:cornerRadius="15dp"
|
||||
app:icon="@drawable/ic_cancel"
|
||||
app:icon="@drawable/exomedia_ic_pause_white"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/active_download_delete"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/active_download_delete"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:cornerRadius="15dp"
|
||||
app:icon="@drawable/baseline_delete_24"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
@ -159,7 +164,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="download_item_data,active_download_cancel" />
|
||||
app:constraint_referenced_ids="download_item_data,active_download_delete" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/from_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/start">
|
||||
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/to_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/end"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@
|
|||
android:paddingTop="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
android:paddingBottom="70dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
|
|
|
|||
41
app/src/main/res/layout/fragment_active.xml
Normal file
41
app/src/main/res/layout/fragment_active.xml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/pause_resume"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="30dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:text="@string/resume"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pause_resume">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -4,6 +4,11 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="200dp"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
|
|
|||
|
|
@ -112,8 +112,11 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="100dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
|
||||
|
|
|
|||
|
|
@ -27,6 +27,28 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:layout_width="wrap_content"
|
||||
app:singleSelection="true"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -135,11 +157,16 @@
|
|||
android:id="@+id/recyclerViewHome"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:scrollbars="none"
|
||||
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="100dp"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
|
@ -22,6 +23,11 @@
|
|||
android:id="@+id/download_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<RelativeLayout
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
||||
|
|
@ -53,7 +55,7 @@
|
|||
android:layout_height="0dp"
|
||||
android:dividerPadding="5dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/download_button_layout"
|
||||
app:layout_constraintBottom_toTopOf="@+id/download_music"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
|
@ -62,15 +64,15 @@
|
|||
android:id="@+id/result_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:scrollbars="none"
|
||||
android:shadowRadius="2"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="17sp"
|
||||
|
|
@ -80,15 +82,15 @@
|
|||
android:id="@+id/author"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom"
|
||||
android:paddingStart="10dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:scrollbars="none"
|
||||
android:shadowRadius="1.5"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="12sp"
|
||||
|
|
@ -115,33 +117,32 @@
|
|||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/download_button_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dp"
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
app:elevation="0dp"
|
||||
android:elevation="0dp"
|
||||
app:borderWidth="0dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:icon="@drawable/ic_music" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="5dp"
|
||||
app:icon="@drawable/ic_video" />
|
||||
|
||||
</LinearLayout>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="10dp"
|
||||
app:elevation="0dp"
|
||||
android:elevation="0dp"
|
||||
app:borderWidth="0dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:ellipsize="end"
|
||||
|
|
@ -85,7 +86,7 @@
|
|||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_button_layout"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
@ -94,53 +95,46 @@
|
|||
android:id="@+id/bottom_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_button_layout"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/download_button_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:orientation="horizontal"
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="10dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:icon="@drawable/ic_music" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="5dp"
|
||||
app:icon="@drawable/ic_video" />
|
||||
|
||||
</LinearLayout>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/title_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="bottom_info,download_button_layout" />
|
||||
app:constraint_referenced_ids="bottom_info,download_music" />
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@
|
|||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -96,10 +95,9 @@
|
|||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/from_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="70dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:errorEnabled="true"
|
||||
android:hint="@string/start">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
|
|
@ -112,10 +110,9 @@
|
|||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/to_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="70dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/end"
|
||||
app:errorEnabled="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/colon">
|
||||
|
||||
|
|
@ -139,6 +136,11 @@
|
|||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="80dp"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<item
|
||||
android:id="@+id/redownload"
|
||||
android:title="@string/redownload"
|
||||
android:icon="@drawable/ic_refresh"
|
||||
android:icon="@drawable/ic_refresh_white"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
|
|
|
|||
|
|
@ -241,8 +241,7 @@
|
|||
<string name="sponsorblock">حاجب شرائح الإعلانات</string>
|
||||
<string name="keep_cache">الاحتفاظ بالملفات المؤقتة</string>
|
||||
<string name="backup">عمل نسخة احتياطية</string>
|
||||
<string name="pause">إيقاف
|
||||
\n</string>
|
||||
<string name="pause">إيقاف</string>
|
||||
<string name="resume">استئناف</string>
|
||||
<string name="updating_download_data">يتم جلب بيانات التحميل</string>
|
||||
<string name="keep_cache_summary">عدم مسح ملفات الكاش بعد اكتمال التحميل</string>
|
||||
|
|
|
|||
|
|
@ -236,8 +236,7 @@
|
|||
<string name="preferred_format_id">Üstünlük Verilən Format ID</string>
|
||||
<string name="download_already_exists">Yükləmə artıq var</string>
|
||||
<string name="preferred_locale">Üstünlük Verilən Yer</string>
|
||||
<string name="pause">Dayandır
|
||||
\n</string>
|
||||
<string name="pause">Dayandır</string>
|
||||
<string name="resume">Təkrar başlat</string>
|
||||
<string name="updating_download_data">Yükləmə Element Məlumatı Yenilənir</string>
|
||||
<string name="keep_cache">Qalığı Saxla</string>
|
||||
|
|
@ -282,7 +281,7 @@
|
|||
<string name="subtitle_format">Titr Formatı
|
||||
\n</string>
|
||||
<string name="hide_thumbnails">Miniatürləri Gizlət</string>
|
||||
<string name="hide_terminal">Sıxacı paylaşma menyusundan gizlət</string>
|
||||
<string name="show_terminal">Sıxacı paylaşma menyusundan gizlət</string>
|
||||
<string name="saved">Saxlanıldı</string>
|
||||
<string name="clear_saved">Saxlanılanları Təmizlə</string>
|
||||
<string name="use_extra_commands">Əlavə Əmrlər Əlavə Et</string>
|
||||
|
|
|
|||
|
|
@ -232,8 +232,7 @@
|
|||
<string name="quick_download">Schneller Download</string>
|
||||
<string name="quick_download_summary">Daten nicht vorab abrufen</string>
|
||||
<string name="download_already_exists">Download bereits vorhanden</string>
|
||||
<string name="pause">Pause
|
||||
\n</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="backup">Sicherung</string>
|
||||
<string name="restore">Wiederherstellen</string>
|
||||
<string name="network_error">Netzwerkfehler</string>
|
||||
|
|
|
|||
|
|
@ -221,8 +221,7 @@
|
|||
<string name="download_now">Λήψη Τώρα</string>
|
||||
<string name="download_already_exists">Η λήψη υπάρχει ήδη</string>
|
||||
<string name="preferred_locale">Προτιμώμενες Τοπικές Ρυθμίσεις</string>
|
||||
<string name="pause">Παύση
|
||||
\n</string>
|
||||
<string name="pause">Παύση</string>
|
||||
<string name="resume">Συνέχεια</string>
|
||||
<string name="incognito">Ανώνυμη Λειτουργία</string>
|
||||
<string name="sponsorblock">SponsorBlock</string>
|
||||
|
|
|
|||
|
|
@ -236,8 +236,7 @@
|
|||
<string name="finished_download_notification_channel_name">Descargas terminadas</string>
|
||||
<string name="finished_download_notification_channel_description">Notificación de descargas finalizadas o defectuosas</string>
|
||||
<string name="preferred_locale">Ubicación preferida</string>
|
||||
<string name="pause">Pausa
|
||||
\n</string>
|
||||
<string name="pause">Pausa</string>
|
||||
<string name="resume">Resumen</string>
|
||||
<string name="updating_download_data">Actualizando los datos de los elementos de la descarga</string>
|
||||
<string name="keep_cache">Conservar la caché</string>
|
||||
|
|
@ -285,7 +284,7 @@
|
|||
\n</string>
|
||||
<string name="hide_thumbnails">Ocultar las miniaturas</string>
|
||||
<string name="saved">Guardado</string>
|
||||
<string name="hide_terminal">Ocultar Terminal del menú compartir</string>
|
||||
<string name="show_terminal">Ocultar Terminal del menú compartir</string>
|
||||
<string name="save_for_later">¿Guardar la descarga para más tarde\?</string>
|
||||
<string name="clear_saved">Borrar lo Guardado</string>
|
||||
</resources>
|
||||
|
|
@ -153,8 +153,7 @@
|
|||
<string name="preferred_format_id">पसंदीदा प्रारूप आईडी</string>
|
||||
<string name="download_now">तुरंत डाउनलोड करें</string>
|
||||
<string name="preferred_locale">पसंदीदा लोकेल</string>
|
||||
<string name="pause">रोको
|
||||
\n</string>
|
||||
<string name="pause">रोको</string>
|
||||
<string name="resume">चालू करो</string>
|
||||
<string name="keep_cache">कैचे रखें</string>
|
||||
<string name="keep_cache_summary">डाउनलोड समाप्त होने के बाद अस्थायी फ़ाइलें न हटाएं</string>
|
||||
|
|
|
|||
|
|
@ -235,8 +235,7 @@
|
|||
<string name="preferred_format_id">Preferensi ID Format</string>
|
||||
<string name="download_now">Unduh Sekarang</string>
|
||||
<string name="remove_audio">Hilangkan Audio</string>
|
||||
<string name="pause">Jeda
|
||||
\n</string>
|
||||
<string name="pause">Jeda</string>
|
||||
<string name="updating_download_data">Memutakhirkan Data Butir Unduhan</string>
|
||||
<string name="preferred_locale">Preferensi Wilayah</string>
|
||||
<string name="resume">Lanjutkan</string>
|
||||
|
|
@ -278,9 +277,8 @@
|
|||
<string name="format_order">Urutan Format</string>
|
||||
<string name="force_keyframes">Paksakan Keyframe saat Pemotongan</string>
|
||||
<string name="force_keyframes_summary">Proses yang lebih lambat, tetapi pemotongannya lebih akurat</string>
|
||||
<string name="hide_terminal">Sembunyikan Terminal dari menu berbagi</string>
|
||||
<string name="subtitle_format">Format Takarir (Subtitle)
|
||||
\n</string>
|
||||
<string name="show_terminal">Sembunyikan Terminal dari menu berbagi</string>
|
||||
<string name="subtitle_format">Format Takarir (Subtitle)</string>
|
||||
<string name="hide_thumbnails">Sembunyikan Keluku (Thumbnail)</string>
|
||||
<string name="clear_saved">Bersihkan yang Disimpan</string>
|
||||
<string name="saved">Disimpan</string>
|
||||
|
|
|
|||
|
|
@ -238,8 +238,7 @@
|
|||
<string name="quick_download_summary">事前にデータを取得しません</string>
|
||||
<string name="remove_audio">音声を削除</string>
|
||||
<string name="download_already_exists">ダウンロードに既に存在します</string>
|
||||
<string name="pause">一時停止
|
||||
\n</string>
|
||||
<string name="pause">一時停止</string>
|
||||
<string name="resume">再開</string>
|
||||
<string name="keep_cache">キャッシュを保持</string>
|
||||
<string name="keep_cache_summary">ダウンロードの完了後に一時ファイルを削除しないようにします</string>
|
||||
|
|
|
|||
|
|
@ -241,8 +241,7 @@
|
|||
<string name="system">시스템</string>
|
||||
<string name="red">빨간색</string>
|
||||
<string name="pure_theme_summary">퓨어 블랙 / 화이트 테마</string>
|
||||
<string name="pause">일시정지
|
||||
\n</string>
|
||||
<string name="pause">일시정지</string>
|
||||
<string name="material_you">머터리얼</string>
|
||||
<string name="green">녹색</string>
|
||||
<string name="blue">파란색</string>
|
||||
|
|
|
|||
|
|
@ -228,8 +228,7 @@
|
|||
<string name="preferred_format_id">Vēlamā Formāta ID</string>
|
||||
<string name="download_now">Lejupielādēt Tagad</string>
|
||||
<string name="download_already_exists">Lejupielāde jau pastāv</string>
|
||||
<string name="pause">Pauze
|
||||
\n</string>
|
||||
<string name="pause">Pauze</string>
|
||||
<string name="updating_download_data">Notiek Lejupielādes Vienuma Datu Atjaunināšana</string>
|
||||
<string name="keep_cache">Paturēt Kešatmiņu</string>
|
||||
<string name="keep_cache_summary">Neizdzēst pagaidu failus pēc lejupielādes pabeigšanas</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="pause">Stans
|
||||
\n</string>
|
||||
<string name="pause">Stans</string>
|
||||
<string name="keep_cache">Behald mellomgøymet</string>
|
||||
<string name="keep_cache_summary">Ikkje slett mellombelse filer etter at hentinga er ferdig</string>
|
||||
<string name="network_error">Nettverksfeil</string>
|
||||
|
|
|
|||
|
|
@ -204,8 +204,7 @@
|
|||
<string name="download_now">Pobierz teraz</string>
|
||||
<string name="download_already_exists">Pobieranie już istnieje</string>
|
||||
<string name="preferred_locale">Preferowane ustawienia regionalne</string>
|
||||
<string name="pause">Pauza
|
||||
\n</string>
|
||||
<string name="pause">Pauza</string>
|
||||
<string name="updating_download_data">Aktualizowanie danych elementu do pobrania</string>
|
||||
<string name="keep_cache_summary">Nie usuwaj plików tymczasowych po zakończeniu pobierania</string>
|
||||
<string name="restore">Przywróć</string>
|
||||
|
|
|
|||
|
|
@ -215,8 +215,7 @@
|
|||
<string name="download_already_exists">O download já existe</string>
|
||||
<string name="keep_cache">Manter Cache</string>
|
||||
<string name="updating_download_data">Atualizando os dados do item de download</string>
|
||||
<string name="pause">Pausar
|
||||
\n</string>
|
||||
<string name="pause">Pausar</string>
|
||||
<string name="preferred_locale">Local preferido</string>
|
||||
<string name="resume">Continuar</string>
|
||||
<string name="network_error">Erro de rede</string>
|
||||
|
|
@ -278,10 +277,9 @@
|
|||
<string name="sponsorblock">Bloqueio de Patrocinadores</string>
|
||||
<string name="force_keyframes">Forçar quadros-chave nos cortes</string>
|
||||
<string name="force_keyframes_summary">Processo lento, mas cortes mais precisos</string>
|
||||
<string name="subtitle_format">Formato da Legenda
|
||||
\n</string>
|
||||
<string name="subtitle_format">Formato da Legenda</string>
|
||||
<string name="hide_thumbnails">Ocultar Miniaturas</string>
|
||||
<string name="hide_terminal">Ocultar Terminal do menu de compartilhamento</string>
|
||||
<string name="show_terminal">Ocultar Terminal do menu de compartilhamento</string>
|
||||
<string name="saved">Salvo</string>
|
||||
<string name="clear_saved">Limpar Salvo</string>
|
||||
<string name="save_for_later">Salvar download para mais tarde\?</string>
|
||||
|
|
|
|||
|
|
@ -168,8 +168,7 @@
|
|||
<string name="download_now">Descarregar agora</string>
|
||||
<string name="download_already_exists">Descarga já existente</string>
|
||||
<string name="preferred_locale">Idioma preferido</string>
|
||||
<string name="pause">Pausa
|
||||
\n</string>
|
||||
<string name="pause">Pausa</string>
|
||||
<string name="resume">Retomar</string>
|
||||
<string name="keep_cache">Manter em cache</string>
|
||||
<string name="backup">Backup</string>
|
||||
|
|
|
|||
|
|
@ -239,8 +239,7 @@
|
|||
<string name="format_filtering_hint">Чтобы использовать эту опцию, все элементы должны быть одного типа</string>
|
||||
<string name="restore_complete">Восстановление приложения завершено. Были восстановлены следующие объекты:</string>
|
||||
<string name="download_already_exists">Загрузка уже существует</string>
|
||||
<string name="pause">Пауза
|
||||
\n</string>
|
||||
<string name="pause">Пауза</string>
|
||||
<string name="preferred_locale">Предпочтительный регион</string>
|
||||
<string name="video_recommendations">Видеорекомендации</string>
|
||||
<string name="couldnt_parse_file">Не удалось разобрать файл</string>
|
||||
|
|
@ -284,7 +283,7 @@
|
|||
<string name="subtitle_format">Формат субтиров
|
||||
\n</string>
|
||||
<string name="hide_thumbnails">Скрыть миниатюры видео</string>
|
||||
<string name="hide_terminal">Скрыть терминал из меню \"Поделиться\"</string>
|
||||
<string name="show_terminal">Скрыть терминал из меню \"Поделиться\"</string>
|
||||
<string name="saved">Сохраненные</string>
|
||||
<string name="clear_saved">Очистить сохраненные</string>
|
||||
<string name="save_for_later">Сохранить загрузку для возврата к ней позднее\?</string>
|
||||
|
|
|
|||
|
|
@ -241,8 +241,7 @@
|
|||
<string name="keep_cache">Mbaj Memoriken Kashe</string>
|
||||
<string name="keep_cache_summary">Mos fshi skedarët e përkohshëm pasi shkarkimi ka mbaruar</string>
|
||||
<string name="restore">Rikthe</string>
|
||||
<string name="pause">Pauzë
|
||||
\n</string>
|
||||
<string name="pause">Pauzë</string>
|
||||
<string name="updating_download_data">Duke Përditësuar Informacionet e Objektit</string>
|
||||
<string name="backup">Ruaj</string>
|
||||
<string name="select_backup_categories">Zgjidh kategoritë për ruajtje</string>
|
||||
|
|
@ -281,7 +280,7 @@
|
|||
<string name="force_keyframes_summary">Proçes më i ngadaltë, por prerje më të sakta</string>
|
||||
<string name="subtitle_format">Formati i Titrave
|
||||
\n</string>
|
||||
<string name="hide_terminal">Fshihe Terminalin nga fleta e shpërndarjes</string>
|
||||
<string name="show_terminal">Fshihe Terminalin nga fleta e shpërndarjes</string>
|
||||
<string name="saved">Të ruajtura</string>
|
||||
<string name="clear_saved">Pastro të ruajturat</string>
|
||||
<string name="save_for_later">Ruaj Shkarkimin për më vonë\?</string>
|
||||
|
|
|
|||
|
|
@ -240,8 +240,7 @@
|
|||
<string name="download_now">Şimdi İndir</string>
|
||||
<string name="remove_audio">Sesi Kaldır</string>
|
||||
<string name="preferred_locale">Tercih Edilen Konum</string>
|
||||
<string name="pause">Duraklat
|
||||
\n</string>
|
||||
<string name="pause">Duraklat</string>
|
||||
<string name="resume">Devam et</string>
|
||||
<string name="updating_download_data">İndirilen Öğe Verilerini Güncelleme</string>
|
||||
<string name="keep_cache">Önbelleği Sakla</string>
|
||||
|
|
|
|||
|
|
@ -236,8 +236,7 @@
|
|||
<string name="download_now">Завантажити зараз</string>
|
||||
<string name="download_already_exists">Завантаження вже існує</string>
|
||||
<string name="preferred_locale">Бажане розташування</string>
|
||||
<string name="pause">Пауза
|
||||
\n</string>
|
||||
<string name="pause">Пауза</string>
|
||||
<string name="resume">Продовжити</string>
|
||||
<string name="updating_download_data">Оновлення даних завантажуваного елемента</string>
|
||||
<string name="keep_cache">Зберегти кеш</string>
|
||||
|
|
@ -282,7 +281,7 @@
|
|||
<string name="current">Поточна команда</string>
|
||||
<string name="use_extra_commands_summary">Додайте свої додаткові команди перед завантаженням аудіо/відео</string>
|
||||
<string name="hide_thumbnails">Приховати мініатюри відео</string>
|
||||
<string name="hide_terminal">Приховати термінал з меню \"Поділитися\"</string>
|
||||
<string name="show_terminal">Приховати термінал з меню \"Поділитися\"</string>
|
||||
<string name="saved">Збережені</string>
|
||||
<string name="clear_saved">Очистити збережені</string>
|
||||
<string name="subtitle_format">Формат субтитрів
|
||||
|
|
|
|||
|
|
@ -122,8 +122,7 @@
|
|||
<string name="download_now">立即下載</string>
|
||||
<string name="download_already_exists">已存在下載</string>
|
||||
<string name="preferred_locale">首選地區設定</string>
|
||||
<string name="pause">暫停
|
||||
\n</string>
|
||||
<string name="pause">暫停</string>
|
||||
<string name="resume">繼續</string>
|
||||
<string name="updating_download_data">正在更新下載項目資料</string>
|
||||
<string name="keep_cache">保留快取</string>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<color name="grey">#323232</color>
|
||||
<color name="light_grey">#A6A6A6</color>
|
||||
<color name="icon_bg">#FFFFFF</color>
|
||||
<color name="icon_fg">#d43c3c</color>
|
||||
<color name="icon_fg">#db2e2e</color>
|
||||
|
||||
|
||||
<color name="blue_md_theme_light_primary">#0058CB</color>
|
||||
|
|
@ -320,9 +320,9 @@
|
|||
<color name="orange_md_theme_dark_errorContainer">#93000A</color>
|
||||
<color name="orange_md_theme_dark_onError">#690005</color>
|
||||
<color name="orange_md_theme_dark_onErrorContainer">#FFDAD6</color>
|
||||
<color name="orange_md_theme_dark_background">#1F1B16</color>
|
||||
<color name="orange_md_theme_dark_background">#1b1b1b</color>
|
||||
<color name="orange_md_theme_dark_onBackground">#EBE1D9</color>
|
||||
<color name="orange_md_theme_dark_surface">#1F1B16</color>
|
||||
<color name="orange_md_theme_dark_surface">#1b1b1b</color>
|
||||
<color name="orange_md_theme_dark_onSurface">#EBE1D9</color>
|
||||
<color name="orange_md_theme_dark_surfaceVariant">#504539</color>
|
||||
<color name="orange_md_theme_dark_onSurfaceVariant">#D4C4B5</color>
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@
|
|||
<string name="download_now">Download Now</string>
|
||||
<string name="download_already_exists">Download already exists</string>
|
||||
<string name="preferred_locale">Preferred Locale</string>
|
||||
<string name="pause">Pause\n</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="resume">Resume</string>
|
||||
<string name="updating_download_data">Updating Download Item Data</string>
|
||||
<string name="keep_cache">Keep Cache</string>
|
||||
|
|
@ -290,7 +290,7 @@
|
|||
<string name="current">Current Command</string>
|
||||
<string name="subtitle_format">Subtitle Format\n</string>
|
||||
<string name="hide_thumbnails">Hide Thumbnails</string>
|
||||
<string name="hide_terminal">Hide Terminal from share menu</string>
|
||||
<string name="show_terminal">Show Terminal in share menu</string>
|
||||
<string name="saved">Saved</string>
|
||||
<string name="clear_saved">Clear Saved</string>
|
||||
<string name="save_for_later">Save Download for Later?</string>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
app:title="@string/socks5_proxy" />
|
||||
|
||||
<ListPreference
|
||||
android:dependency="download_card"
|
||||
android:defaultValue="video"
|
||||
android:entries="@array/download_types"
|
||||
android:entryValues="@array/download_types_values"
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@
|
|||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_share_24"
|
||||
android:key="hide_terminal"
|
||||
app:title="@string/hide_terminal" />
|
||||
android:key="show_terminal"
|
||||
app:title="@string/show_terminal" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
Loading…
Reference in a new issue