Merge branch 'main' into weblate-ytdlnis-strings
This commit is contained in:
commit
f309f0813b
67 changed files with 881 additions and 434 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">Sichern</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,8 +277,7 @@
|
|||
<string name="sponsorblock">Bloqueio do Patrocinador</string>
|
||||
<string name="force_keyframes">Forçar quadros-chave nos cortes</string>
|
||||
<string name="force_keyframes_summary">Processo mais 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="saved">Salvou</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>
|
||||
|
|
@ -281,8 +280,7 @@
|
|||
<string name="use_extra_commands_summary">Добавьте свои дополнительные команды перед загрузкой аудио/видео</string>
|
||||
<string name="use_extra_commands">Дополнительные команды</string>
|
||||
<string name="current">Текущая команда</string>
|
||||
<string name="subtitle_format">Формат субтитров
|
||||
\n</string>
|
||||
<string name="subtitle_format">Формат субтитров</string>
|
||||
<string name="hide_thumbnails">Скрыть миниатюры</string>
|
||||
<string name="hide_terminal">Скрыть терминал из меню «Поделиться»</string>
|
||||
<string name="saved">Сохранено</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>
|
||||
|
|
|
|||
|
|
@ -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