CHANGELOG
Added option to turn off usage of cookies Some fixes with the cut screen Added ability to save command templates as extra commands by default on every downloadcard/AddExtraCommandsDialog fixed app not saving the proper youtube link and having to refetch data unnecessarily removed question mark from settings restore dialog fixed app scrolling in the tablayout in the download queue screen while you are dragging the vertical scrollbar fixed app not destroying active downloads when you terminate the app
This commit is contained in:
parent
bc3bcbf58b
commit
c44929d5cb
60 changed files with 803 additions and 415 deletions
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
|||
def versionMajor = 1
|
||||
def versionMinor = 6
|
||||
def versionPatch = 3
|
||||
def versionBuild = 10 // bump for dogfood builds, public betas, etc.
|
||||
def versionBuild = 13 // bump for dogfood builds, public betas, etc.
|
||||
def versionExt = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
|
|
@ -152,18 +152,13 @@ dependencies {
|
|||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navVer"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navVer"
|
||||
implementation 'androidx.core:core-ktx:1.10.0'
|
||||
implementation 'androidx.core:core-ktx:1.10.1'
|
||||
implementation 'androidx.test.ext:junit-ktx:1.1.5'
|
||||
implementation 'androidx.benchmark:benchmark-macro:1.1.1'
|
||||
testImplementation "junit:junit:$junitVer"
|
||||
androidTestImplementation "junit:junit:$junitVer"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidJunitVer"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVer"
|
||||
androidTestImplementation "androidx.benchmark:benchmark-macro-junit4:1.2.0-alpha16"
|
||||
androidTestImplementation "androidx.test:runner:1.5.2"
|
||||
androidTestImplementation "androidx.test:core:1.5.0"
|
||||
androidTestImplementation "androidx.test:rules:1.5.0"
|
||||
androidTestImplementation "androidx.navigation:navigation-testing:$navVer"
|
||||
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
implementation "com.devbrackets.android:exomedia:4.3.0"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 9,
|
||||
"identityHash": "bcd20f64b54fbc6e470be0d15059a66e",
|
||||
"identityHash": "d29e09789b7c96b5551b80da253b7330",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
|
|
@ -180,7 +180,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "downloads",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER, `workID` BLOB)",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
|
@ -324,12 +324,6 @@
|
|||
"columnName": "logID",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "workID",
|
||||
"columnName": "workID",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
|
@ -343,7 +337,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "commandTemplates",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `useAsExtraCommand` INTEGER NOT NULL DEFAULT false)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
|
@ -362,6 +356,13 @@
|
|||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommand",
|
||||
"columnName": "useAsExtraCommand",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "false"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
|
@ -511,7 +512,7 @@
|
|||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bcd20f64b54fbc6e470be0d15059a66e')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd29e09789b7c96b5551b80da253b7330')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.deniscerri.ytdlnis
|
||||
|
||||
import android.app.Application
|
||||
import android.os.Looper
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
|
|
@ -66,7 +67,9 @@ class App : Application() {
|
|||
)
|
||||
|
||||
}catch (e: Exception){
|
||||
Toast.makeText(this@App, e.message, Toast.LENGTH_SHORT).show()
|
||||
Looper.prepare().runCatching {
|
||||
Toast.makeText(this@App, e.message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.navOptions
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
|
|
@ -56,7 +57,10 @@ import com.google.android.material.navigation.NavigationBarView
|
|||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.navigationrail.NavigationRailView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
|
|
@ -116,14 +120,14 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
||||
graph.setStartDestination(R.id.homeFragment)
|
||||
when(sharedPreferences.getString("start_destination", "")) {
|
||||
"History" -> graph.setStartDestination(R.id.historyFragment)
|
||||
"More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
||||
}
|
||||
|
||||
navController.graph = graph
|
||||
// val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
||||
// graph.setStartDestination(R.id.homeFragment)
|
||||
// when(sharedPreferences.getString("start_destination", "")) {
|
||||
// "History" -> graph.setStartDestination(R.id.historyFragment)
|
||||
// "More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
||||
// }
|
||||
//
|
||||
// navController.graph = graph
|
||||
|
||||
if (navigationView is NavigationBarView){
|
||||
(navigationView as NavigationBarView).setupWithNavController(navController)
|
||||
|
|
@ -172,11 +176,24 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
terminateDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
terminateDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
if (doNotShowAgain){
|
||||
sharedPreferences.edit().putBoolean("ask_terminate_app", false).apply()
|
||||
runBlocking {
|
||||
val job : Job = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val activeDownloads = downloadViewModel.getActiveDownloads().toMutableList()
|
||||
activeDownloads.map { it.status = DownloadRepository.Status.Queued.toString() }
|
||||
activeDownloads.forEach {
|
||||
downloadViewModel.updateDownload(it)
|
||||
}
|
||||
}
|
||||
runBlocking {
|
||||
job.join()
|
||||
if (doNotShowAgain){
|
||||
sharedPreferences.edit().putBoolean("ask_terminate_app", false).apply()
|
||||
}
|
||||
finishAndRemoveTask()
|
||||
finishAffinity()
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
finishAndRemoveTask()
|
||||
exitProcess(0)
|
||||
}
|
||||
terminateDialog.show()
|
||||
}else{
|
||||
|
|
@ -216,6 +233,14 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putBundle("nav_state", navController.saveState())
|
||||
}
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
navController.restoreState(savedInstanceState.getBundle("nav_state"))
|
||||
}
|
||||
|
||||
private fun View.visibilityChanged(action: (View) -> Unit) {
|
||||
this.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
|
|
|
|||
|
|
@ -148,16 +148,10 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.opengl.Visibility
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -46,18 +47,16 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
|||
val content = card.findViewById<TextView>(R.id.content)
|
||||
content.text = item?.content
|
||||
|
||||
// val check = card.findViewById<Button>(R.id.check)
|
||||
//
|
||||
// check.setOnClickListener {
|
||||
// onItemClickListener.onSelected(item!!)
|
||||
// }
|
||||
val useInExtraCommands = card.findViewById<TextView>(R.id.useInExtraCommands)
|
||||
if (item!!.useAsExtraCommand) useInExtraCommands.visibility = View.VISIBLE
|
||||
else useInExtraCommands.visibility = View.GONE
|
||||
|
||||
card.setOnClickListener {
|
||||
onItemClickListener.onItemClick(item!!, position)
|
||||
onItemClickListener.onItemClick(item, position)
|
||||
}
|
||||
|
||||
card.setOnLongClickListener {
|
||||
onItemClickListener.onDelete(item!!); true
|
||||
onItemClickListener.onDelete(item); true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
@TypeConverters(Converters::class)
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class, LogItem::class],
|
||||
version = 8,
|
||||
version = 9,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
|
|
@ -16,7 +16,8 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
AutoMigration (from = 4, to = 5),
|
||||
AutoMigration (from = 5, to = 6),
|
||||
AutoMigration (from = 6, to = 7),
|
||||
AutoMigration (from = 7, to = 8)
|
||||
AutoMigration (from = 7, to = 8),
|
||||
AutoMigration (from = 8, to = 9)
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ interface CommandTemplateDao {
|
|||
|
||||
@Query("SELECT * FROM commandTemplates ORDER BY id DESC")
|
||||
fun getAllTemplatesFlow() : Flow<List<CommandTemplate>>
|
||||
@Query("SELECT content FROM commandTemplates WHERE useAsExtraCommand is 1")
|
||||
fun getAllTemplatesAsExtraCommands() : List<String>
|
||||
|
||||
@Query("SELECT * FROM templateShortcuts ORDER BY id DESC")
|
||||
fun getAllShortcutsFlow() : Flow<List<TemplateShortcut>>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
|
@ -10,5 +11,7 @@ data class CommandTemplate(
|
|||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
var title: String,
|
||||
var content: String
|
||||
var content: String,
|
||||
@ColumnInfo(defaultValue = "false")
|
||||
var useAsExtraCommand: Boolean
|
||||
)
|
||||
|
|
@ -8,7 +8,7 @@ import androidx.room.PrimaryKey
|
|||
data class ResultItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
val url: String,
|
||||
var url: String,
|
||||
var title: String,
|
||||
var author: String,
|
||||
val duration: String,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
|
|||
suspend fun getOne(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?>{
|
||||
val infoUtil = InfoUtil(context)
|
||||
try {
|
||||
val v = infoUtil.getVideo(inputQuery)
|
||||
val v = infoUtil.getYoutubeVideo(inputQuery)
|
||||
if (resetResults) {
|
||||
deleteAll()
|
||||
itemCount.value = v.size
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.content.res.Resources
|
|||
import android.net.ConnectivityManager
|
||||
import android.os.Looper
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
|
|
@ -18,8 +19,10 @@ import androidx.work.Constraints
|
|||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkRequest
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
|
|
@ -42,8 +45,11 @@ import com.google.gson.Gson
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
@ -71,6 +77,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
private val formatIDPreference: List<String>
|
||||
private val audioFormatIDPreference: List<String>
|
||||
private val resources : Resources
|
||||
private var extraCommands: String = ""
|
||||
enum class Type {
|
||||
audio, video, command
|
||||
}
|
||||
|
|
@ -90,6 +97,11 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
savedDownloads = repository.savedDownloads.asLiveData()
|
||||
cancelledDownloads = repository.cancelledDownloads.asLiveData()
|
||||
erroredDownloads = repository.erroredDownloads.asLiveData()
|
||||
viewModelScope.launch(Dispatchers.IO){
|
||||
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||
extraCommands = commandTemplateDao.getAllTemplatesAsExtraCommands().joinToString(" ")
|
||||
}
|
||||
}
|
||||
|
||||
videoQualityPreference = sharedPreferences.getString("video_quality", application.getString(R.string.best_quality)).toString()
|
||||
formatIDPreference = sharedPreferences.getString("format_id", "").toString().split(",")
|
||||
|
|
@ -190,7 +202,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
container!!,
|
||||
"",
|
||||
resultItem.formats,
|
||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences, extraCommands, customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -312,7 +324,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
container,
|
||||
"",
|
||||
ArrayList(),
|
||||
path, historyItem.website, "", "", audioPreferences, videoPreferences, "", customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
path, historyItem.website, "", "", audioPreferences, videoPreferences, extraCommands, customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -415,6 +427,12 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
repository.insert(item)
|
||||
}
|
||||
|
||||
fun insertAll(items: List<DownloadItem>)= viewModelScope.launch(Dispatchers.IO){
|
||||
items.forEach{
|
||||
repository.insert(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCancelled() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.deleteCancelled()
|
||||
}
|
||||
|
|
@ -473,10 +491,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
exists = true
|
||||
}else{
|
||||
if (it.id == 0L){
|
||||
val insert = async {repository.insert(it)}
|
||||
val id = insert.await()
|
||||
val id = runBlocking {repository.insert(it)}
|
||||
it.id = id
|
||||
}else{
|
||||
}else if (it.status == DownloadRepository.Status.Queued.toString()){
|
||||
repository.update(it)
|
||||
}
|
||||
|
||||
|
|
@ -489,7 +506,6 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Toast.makeText(context, context.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
queuedItems.forEach {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
var delay = if (it.downloadStartTime != 0L){
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ class ShareActivity : BaseActivity() {
|
|||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private var quickDownload by Delegates.notNull<Boolean>()
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
|
||||
class AddExtraCommandsDialog(private val item: DownloadItem, private val callback: ExtraCommandsListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
// Inflate the layout to use as dialog or embedded fragment
|
||||
return inflater.inflate(R.layout.extra_commands_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
return dialog
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("RestrictedApi", "SetTextI18n", "UseGetLayoutInflater")
|
||||
override fun setupDialog(dialog: Dialog, style: Int) {
|
||||
super.setupDialog(dialog, style)
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE or
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.result_card_details, null)
|
||||
dialog.setContentView(view)
|
||||
|
||||
|
||||
}
|
||||
|
||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val behavior = BottomSheetBehavior.from(view.parent as View)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
|
||||
val text = view.findViewById<EditText>(R.id.command)
|
||||
val templates = view.findViewById<Button>(R.id.commands)
|
||||
val shortcuts = view.findViewById<Button>(R.id.shortcuts)
|
||||
val currentCommand = infoUtil.buildYoutubeDLRequest(item).buildCommand().joinToString(" ")
|
||||
view.findViewById<TextView>(R.id.currentText)?.text = currentCommand
|
||||
|
||||
text?.setText(item.extraCommands)
|
||||
|
||||
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
text!!.postDelayed({
|
||||
text.setSelection(text.length())
|
||||
text.requestFocus()
|
||||
imm.showSoftInput(text, 0)
|
||||
}, 300)
|
||||
|
||||
var templateCount = 0
|
||||
var shortcutCount = 0
|
||||
lifecycleScope.launch {
|
||||
templateCount = withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.getTotalNumber()
|
||||
}
|
||||
templates.isEnabled = templateCount != 0
|
||||
|
||||
shortcutCount = withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.getTotalShortcutNumber()
|
||||
}
|
||||
shortcuts.isEnabled = shortcutCount != 0
|
||||
|
||||
}
|
||||
|
||||
templates.setOnClickListener {
|
||||
if (templateCount == 0){
|
||||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ template ->
|
||||
text.text.insert(text.selectionStart, "${template.content} ")
|
||||
text.postDelayed({
|
||||
text.requestFocus()
|
||||
imm.showSoftInput(text, 0)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shortcuts.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
if (shortcutCount > 0){
|
||||
UiUtil.showShortcuts(requireActivity(), commandTemplateViewModel) {sh ->
|
||||
text.text.insert(text.selectionStart, " $sh ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ok = view.findViewById<Button>(R.id.okButton)
|
||||
ok?.setOnClickListener {
|
||||
callback.onChangeExtraCommand(text.text.toString())
|
||||
this.dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
super.onCancel(dialog)
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
|
||||
private fun cleanUp(){
|
||||
kotlin.runCatching {
|
||||
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("extraCommands")!!).commit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface ExtraCommandsListener {
|
||||
fun onChangeExtraCommand(c: String)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import android.graphics.Color
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Range
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
|
@ -58,7 +59,7 @@ import java.util.concurrent.Executors
|
|||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var player: ExoPlayer
|
||||
|
|
@ -84,7 +85,6 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
private var timeSeconds by Delegates.notNull<Int>()
|
||||
private lateinit var selectedCuts: MutableList<String>
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
|
|
@ -157,12 +157,12 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
if (urls.isNullOrEmpty()) {
|
||||
infoUtil.getStreamingUrlAndChapters(item.url)
|
||||
}else {
|
||||
urls.split("\n").toMutableList()
|
||||
urls!!.split("\n").toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isEmpty()) throw Exception("No Data found!")
|
||||
if (chapters!!.isEmpty()){
|
||||
if (chapters!!.isEmpty() && urls!!.isBlank()){
|
||||
try{
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
chapters = Gson().fromJson(data.first().toString(), listType)
|
||||
|
|
@ -239,26 +239,31 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
fromTextInput.editText!!.setText("0:00")
|
||||
toTextInput.editText!!.setText(item.duration)
|
||||
|
||||
rangeSlider.addOnChangeListener { rangeSlider, _, _ ->
|
||||
val values = rangeSlider.values
|
||||
val startTimestamp = (values[0].toInt() * timeSeconds) / 100
|
||||
val endTimestamp = (values[1].toInt() * timeSeconds) / 100
|
||||
rangeSlider.addOnSliderTouchListener(object : RangeSlider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: RangeSlider) {
|
||||
|
||||
val startTimestampString = infoUtil.formatIntegerDuration(startTimestamp, Locale.US)
|
||||
val endTimestampString = infoUtil.formatIntegerDuration(endTimestamp, Locale.US)
|
||||
}
|
||||
|
||||
fromTextInput.editText!!.setText(startTimestampString)
|
||||
toTextInput.editText!!.setText(endTimestampString)
|
||||
override fun onStopTrackingTouch(slider: RangeSlider) {
|
||||
val values = rangeSlider.values
|
||||
val startTimestamp = (values[0].toInt() * timeSeconds) / 100
|
||||
val endTimestamp = (values[1].toInt() * timeSeconds) / 100
|
||||
|
||||
val startTimestampString = infoUtil.formatIntegerDuration(startTimestamp, Locale.US)
|
||||
val endTimestampString = infoUtil.formatIntegerDuration(endTimestamp, Locale.US)
|
||||
|
||||
fromTextInput.editText!!.setText(startTimestampString)
|
||||
toTextInput.editText!!.setText(endTimestampString)
|
||||
|
||||
|
||||
okBtn.isEnabled = !(values[0] == 0F && values[1] == 100F)
|
||||
okBtn.isEnabled = !(values[0] == 0F && values[1] == 100F)
|
||||
|
||||
try {
|
||||
player.seekTo((startTimestamp * 1000).toLong())
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
|
||||
}
|
||||
try {
|
||||
player.seekTo((startTimestamp * 1000).toLong())
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
}
|
||||
})
|
||||
|
||||
fromTextInput.editText!!.setOnKeyListener(object : View.OnKeyListener {
|
||||
|
||||
|
|
@ -271,20 +276,23 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
|
||||
fromTextInput.editText!!.clearFocus()
|
||||
val seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||
if (seconds == 0) {
|
||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||
return true
|
||||
}
|
||||
val endSeconds = convertStringToTimestamp(toTextInput.editText!!.text.toString())
|
||||
|
||||
val startValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
if (startValue > 100){
|
||||
val endValue = (endSeconds.toFloat() / endTimestamp) * 100
|
||||
|
||||
if (seconds == 0) {
|
||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||
}else if (startValue > 100){
|
||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||
return true
|
||||
}
|
||||
|
||||
rangeSlider.setValues(startValue, rangeSlider.valueTo)
|
||||
val startValueTimeStampSeconds = (startValue.toInt() * timeSeconds) / 100
|
||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startValueTimeStampSeconds, Locale.US))
|
||||
rangeSlider.setValues(startValue, endValue)
|
||||
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||
try {
|
||||
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -299,24 +307,28 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
if ((event!!.action == KeyEvent.ACTION_DOWN) &&
|
||||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||
|
||||
val values = rangeSlider.values
|
||||
val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
||||
|
||||
toTextInput.editText!!.clearFocus()
|
||||
val startSeconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||
val seconds = convertStringToTimestamp(toTextInput.editText!!.text.toString())
|
||||
|
||||
val startValue = (startSeconds.toFloat() / endTimestamp) * 100
|
||||
val endValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
|
||||
if (seconds == 0) {
|
||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||
return true
|
||||
}
|
||||
|
||||
val endValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
if (endValue > 100 || endValue <= rangeSlider.valueFrom.toInt()){
|
||||
}else if (endValue > 100 || endValue <= rangeSlider.valueFrom.toInt()){
|
||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||
return true
|
||||
}
|
||||
|
||||
rangeSlider.setValues(rangeSlider.valueFrom, endValue)
|
||||
val endValueTimeStampSeconds = (endValue.toInt() * timeSeconds) / 100
|
||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endValueTimeStampSeconds, Locale.US))
|
||||
rangeSlider.setValues(startValue, endValue)
|
||||
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||
try {
|
||||
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.deniscerri.ytdlnis.database.models.ResultItem
|
|||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.ExtraCommandsBottomSheetBinding
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
|
|
@ -348,37 +349,14 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||
extraCommands.visibility = View.VISIBLE
|
||||
extraCommands.setOnClickListener {
|
||||
val bottomSheet = BottomSheetDialog(requireContext())
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.extra_commands_bottom_sheet)
|
||||
|
||||
val text = bottomSheet.findViewById<EditText>(R.id.command)
|
||||
val currentCommand = infoUtil.buildYoutubeDLRequest(downloadItem).buildCommand().joinToString(" ")
|
||||
bottomSheet.findViewById<TextView>(R.id.currentText)?.text = currentCommand
|
||||
|
||||
text?.setText(downloadItem.extraCommands)
|
||||
|
||||
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
text!!.postDelayed({
|
||||
text.setSelection(text.length())
|
||||
text.requestFocus()
|
||||
imm.showSoftInput(text, 0)
|
||||
}, 300)
|
||||
|
||||
val ok = bottomSheet.findViewById<Button>(R.id.okButton)
|
||||
ok?.setOnClickListener {
|
||||
downloadItem.extraCommands = text.text.toString()
|
||||
bottomSheet.dismiss()
|
||||
val callback = object : ExtraCommandsListener {
|
||||
override fun onChangeExtraCommand(c: String) {
|
||||
downloadItem.extraCommands = c
|
||||
}
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
val bottomSheetDialog = AddExtraCommandsDialog(downloadItem, callback)
|
||||
bottomSheetDialog.show(parentFragmentManager, "extraCommands")
|
||||
}
|
||||
}else{
|
||||
extraCommands.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
val editSelected : Chip = view.findViewById(R.id.editSelected)
|
||||
editSelected.setOnClickListener {
|
||||
var current = templates.find { it.title == autoCompleteTextView.text.toString() }
|
||||
if (current == null) current = CommandTemplate(0, "", chosenCommandView.editText!!.text.toString())
|
||||
if (current == null) current = CommandTemplate(0, "", chosenCommandView.editText!!.text.toString(), false)
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
templates.add(it)
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
|
@ -145,10 +145,10 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
dd.setTitle(getString(R.string.save_for_later))
|
||||
dd.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
lifecycleScope.launch(Dispatchers.IO){
|
||||
items.forEach {
|
||||
it.status = DownloadRepository.Status.Saved.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
lifecycleScope.launch{
|
||||
items.map { it.status = DownloadRepository.Status.Saved.toString() }
|
||||
withContext(Dispatchers.IO){
|
||||
downloadViewModel.insertAll(items)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,37 +408,14 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||
extraCommands.visibility = View.VISIBLE
|
||||
extraCommands.setOnClickListener {
|
||||
val bottomSheet = BottomSheetDialog(requireContext())
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.extra_commands_bottom_sheet)
|
||||
|
||||
val text = bottomSheet.findViewById<EditText>(R.id.command)
|
||||
val currentCommand = infoUtil.buildYoutubeDLRequest(downloadItem).buildCommand().joinToString(" ")
|
||||
bottomSheet.findViewById<TextView>(R.id.currentText)?.text = currentCommand
|
||||
|
||||
text?.setText(downloadItem.extraCommands)
|
||||
|
||||
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
text!!.postDelayed({
|
||||
text.setSelection(text.length())
|
||||
text.requestFocus()
|
||||
imm.showSoftInput(text, 0)
|
||||
}, 300)
|
||||
|
||||
val ok = bottomSheet.findViewById<Button>(R.id.okButton)
|
||||
ok?.setOnClickListener {
|
||||
downloadItem.extraCommands = text.text.toString()
|
||||
bottomSheet.dismiss()
|
||||
val callback = object : ExtraCommandsListener {
|
||||
override fun onChangeExtraCommand(c: String) {
|
||||
downloadItem.extraCommands = c
|
||||
}
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
val bottomSheetDialog = AddExtraCommandsDialog(downloadItem, callback)
|
||||
bottomSheetDialog.show(parentFragmentManager, "extraCommands")
|
||||
}
|
||||
}else{
|
||||
extraCommands.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.allViews
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
|
@ -20,11 +25,15 @@ 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.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode
|
||||
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.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
|
|
@ -62,45 +71,47 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
)
|
||||
|
||||
activeRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
activeRecyclerView.forceFastScrollMode()
|
||||
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)
|
||||
lifecycleScope.launch {
|
||||
runBlocking {
|
||||
val queued = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getQueued()
|
||||
}
|
||||
queued.forEach {
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(it.id.toString())
|
||||
}
|
||||
}
|
||||
|
||||
list.forEach {
|
||||
cancelItem(it.id.toInt())
|
||||
it.status = DownloadRepository.Status.Paused.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
}
|
||||
|
||||
activeDownloads.notifyDataSetChanged()
|
||||
|
||||
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)
|
||||
lifecycleScope.launch {
|
||||
val toQueue = list.filter { it.status == DownloadRepository.Status.Paused.toString() }.toMutableList()
|
||||
toQueue.forEach {
|
||||
it.status = DownloadRepository.Status.Active.toString()
|
||||
downloadViewModel.updateDownload(it)
|
||||
}
|
||||
val queuedItems = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getQueued()
|
||||
}
|
||||
toQueue.addAll(queuedItems)
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(toQueue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +120,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
list = it
|
||||
activeDownloads.submitList(it)
|
||||
|
||||
if (list.isNotEmpty()){
|
||||
if (it.size > 1){
|
||||
pauseResume.visibility = View.VISIBLE
|
||||
if (list.all { l -> l.status == DownloadRepository.Status.Paused.toString() }){
|
||||
pauseResume.text = requireContext().getString(R.string.resume)
|
||||
|
|
@ -117,6 +128,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
pauseResume.text = requireContext().getString(R.string.pause)
|
||||
}
|
||||
}else{
|
||||
activeDownloads.notifyDataSetChanged()
|
||||
pauseResume.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +143,6 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
|
||||
val progress = work.progress.getInt("progress", 0)
|
||||
val output = work.progress.getString("output")
|
||||
val log = work.progress.getBoolean("log", false)
|
||||
|
||||
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
||||
val outputText = view.findViewWithTag<TextView>("$id##output")
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
|
|
@ -32,6 +35,7 @@ import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
|||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
|
|
@ -75,6 +79,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
)
|
||||
|
||||
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
cancelledRecyclerView.forceFastScrollMode()
|
||||
cancelledRecyclerView.adapter = cancelledDownloads
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
if (preferences.getBoolean("swipe_gestures", true)){
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class DownloadQueueMainFragment : Fragment(){
|
|||
when(m.itemId){
|
||||
R.id.clear_queue -> {
|
||||
showDeleteDialog {
|
||||
downloadViewModel.cancelQueued()
|
||||
cancelAllDownloads()
|
||||
}
|
||||
}
|
||||
R.id.clear_cancelled -> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Canvas
|
||||
|
|
@ -9,6 +10,7 @@ import android.util.DisplayMetrics
|
|||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
|
|
@ -33,6 +35,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
|
|
@ -75,6 +78,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
)
|
||||
|
||||
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
erroredRecyclerView.forceFastScrollMode()
|
||||
erroredRecyclerView.adapter = erroredDownloads
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
if (preferences.getBoolean("swipe_gestures", true)){
|
||||
|
|
|
|||
|
|
@ -8,13 +8,16 @@ import android.graphics.Color
|
|||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
|
@ -37,6 +40,7 @@ import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
|||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
|
|
@ -91,6 +95,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
)
|
||||
|
||||
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
queuedRecyclerView.forceFastScrollMode()
|
||||
queuedRecyclerView.adapter = queuedDownloads
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
if (preferences.getBoolean("swipe_gestures", true)){
|
||||
|
|
@ -427,5 +432,4 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Canvas
|
||||
|
|
@ -9,6 +10,7 @@ import android.util.DisplayMetrics
|
|||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
|
|
@ -31,6 +33,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
|
|
@ -74,6 +77,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
)
|
||||
|
||||
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
savedRecyclerView.forceFastScrollMode()
|
||||
savedRecyclerView.adapter = savedDownloads
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
if (preferences.getBoolean("swipe_gestures", true)){
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.ui.more
|
|||
import android.content.Context.INPUT_METHOD_SERVICE
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
|
|
@ -14,6 +15,7 @@ import android.view.inputmethod.InputMethodManager
|
|||
import android.widget.EditText
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.children
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
|
@ -30,6 +32,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
|||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.materialswitch.MaterialSwitch
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||
|
|
@ -42,22 +45,26 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var listAdapter: CookieAdapter
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var useCookies : MaterialSwitch
|
||||
private lateinit var cookiesViewModel: CookieViewModel
|
||||
private lateinit var cookiesList: List<CookieItem>
|
||||
private lateinit var noResults : RelativeLayout
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var preferences: SharedPreferences
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
mainActivity = activity as MainActivity
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
return inflater.inflate(R.layout.fragment_cookies, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
topAppBar = view.findViewById(R.id.logs_toolbar)
|
||||
useCookies = view.findViewById(R.id.use_cookies)
|
||||
topAppBar.setNavigationOnClickListener { mainActivity.onBackPressedDispatcher.onBackPressed() }
|
||||
cookiesList = listOf()
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
|
|
@ -67,6 +74,7 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
this,
|
||||
mainActivity
|
||||
)
|
||||
val newCookie = view.findViewById<Chip>(R.id.newCookie)
|
||||
recyclerView = view.findViewById(R.id.template_recyclerview)
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = listAdapter
|
||||
|
|
@ -85,6 +93,16 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
}
|
||||
initMenu()
|
||||
initChips()
|
||||
|
||||
|
||||
useCookies.setOnCheckedChangeListener { compoundButton, b ->
|
||||
newCookie.isEnabled = useCookies.isChecked
|
||||
preferences.edit().putBoolean("use_cookies", useCookies.isChecked).apply()
|
||||
}
|
||||
|
||||
val useCookiesPref = preferences.getBoolean("use_cookies", false)
|
||||
useCookies.isChecked = useCookiesPref
|
||||
newCookie.isEnabled = useCookiesPref
|
||||
}
|
||||
|
||||
private fun initMenu() {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,24 @@ import android.view.ViewGroup
|
|||
import android.widget.CheckBox
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class MoreFragment : Fragment() {
|
||||
|
|
@ -29,12 +41,14 @@ class MoreFragment : Fragment() {
|
|||
private lateinit var terminateApp: TextView
|
||||
private lateinit var settings: TextView
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
mainActivity = activity as MainActivity
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return inflater.inflate(R.layout.fragment_more, container, false)
|
||||
}
|
||||
|
||||
|
|
@ -97,14 +111,27 @@ class MoreFragment : Fragment() {
|
|||
}
|
||||
|
||||
terminateDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
terminateDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
if (doNotShowAgain){
|
||||
mainSharedPreferencesEditor.putBoolean("ask_terminate_app", false)
|
||||
mainSharedPreferencesEditor.commit()
|
||||
terminateDialog.setPositiveButton(getString(R.string.ok)) { diag: DialogInterface?, _: Int ->
|
||||
runBlocking {
|
||||
val job : Job = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val activeDownloads = downloadViewModel.getActiveDownloads().toMutableList()
|
||||
activeDownloads.map { it.status = DownloadRepository.Status.Queued.toString() }
|
||||
activeDownloads.forEach {
|
||||
downloadViewModel.updateDownload(it)
|
||||
}
|
||||
}
|
||||
runBlocking {
|
||||
job.join()
|
||||
if (doNotShowAgain){
|
||||
mainSharedPreferencesEditor.putBoolean("ask_terminate_app", false)
|
||||
mainSharedPreferencesEditor.commit()
|
||||
}
|
||||
mainActivity.finishAndRemoveTask()
|
||||
mainActivity.finishAffinity()
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
mainActivity.finishAndRemoveTask()
|
||||
mainActivity.finishAffinity()
|
||||
exitProcess(0)
|
||||
|
||||
}
|
||||
terminateDialog.show()
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -129,8 +129,12 @@ class TerminalActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
R.id.shortcuts -> {
|
||||
if (shortcutCount > 0){
|
||||
showShortcuts()
|
||||
lifecycleScope.launch {
|
||||
if (shortcutCount > 0){
|
||||
UiUtil.showShortcuts(this@TerminalActivity, commandTemplateViewModel){sh ->
|
||||
input!!.text.insert(input!!.selectionStart, "$sh ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.folder -> {
|
||||
|
|
@ -295,35 +299,6 @@ class TerminalActivity : BaseActivity() {
|
|||
topAppBar!!.menu.forEach { it.isEnabled = false }
|
||||
}
|
||||
|
||||
private fun showShortcuts() {
|
||||
lifecycleScope.launch {
|
||||
val bottomSheet = BottomSheetDialog(this@TerminalActivity)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.template_shortcuts_list)
|
||||
|
||||
val chipGroup = bottomSheet.findViewById<ChipGroup>(R.id.shortcutsChipGroup)
|
||||
val shortcutList = withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.getAllShortcuts()
|
||||
}
|
||||
|
||||
chipGroup!!.removeAllViews()
|
||||
shortcutList.forEach {shortcut ->
|
||||
val chip = layoutInflater.inflate(R.layout.suggestion_chip, chipGroup, false) as Chip
|
||||
chip.text = shortcut.content
|
||||
chip.setOnClickListener {
|
||||
input!!.text.insert(input!!.selectionStart, shortcut.content + " ")
|
||||
}
|
||||
chipGroup.addView(chip)
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var commandPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
|
|
|
|||
|
|
@ -550,8 +550,6 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
}
|
||||
|
||||
finalMessage.append("${getString(R.string.restart)}?")
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(getString(R.string.restore))
|
||||
builder.setMessage(finalMessage)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ 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
|
||||
|
|
@ -134,15 +133,17 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun getVideo(url: String): List<ResultItem?> {
|
||||
fun getYoutubeVideo(url: String): List<ResultItem?> {
|
||||
return try {
|
||||
val id = getIDFromYoutubeURL(url)
|
||||
val res = genericRequest("$pipedURL/streams/$id")
|
||||
if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON(
|
||||
res, id
|
||||
res, url
|
||||
))
|
||||
}catch (e: Exception){
|
||||
getFromYTDL(url)
|
||||
val v = getFromYTDL(url)
|
||||
v.forEach { it!!.url = url }
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,9 +173,11 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
return video
|
||||
}
|
||||
private fun createVideoFromPipedJSON(obj: JSONObject, id: String): ResultItem? {
|
||||
private fun createVideoFromPipedJSON(obj: JSONObject, url: String): ResultItem? {
|
||||
var video: ResultItem? = null
|
||||
try {
|
||||
|
||||
val id = getIDFromYoutubeURL(url)
|
||||
val title = Html.fromHtml(obj.getString("title").toString()).toString()
|
||||
val author = try {
|
||||
Html.fromHtml(obj.getString("uploader").toString()).toString()
|
||||
|
|
@ -184,7 +187,6 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
val duration = formatIntegerDuration(obj.getInt("duration"), Locale.US)
|
||||
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
|
||||
val url = "https://www.youtube.com/watch?v=$id"
|
||||
val formats : ArrayList<Format> = ArrayList()
|
||||
|
||||
if(sharedPreferences.getString("formats_source", "yt-dlp") == "piped"){
|
||||
|
|
@ -452,9 +454,12 @@ class InfoUtil(private val context: Context) {
|
|||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()) {
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
|
||||
if (sharedPreferences.getBoolean("use_cookies", false)){
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()) {
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
val proxy = sharedPreferences.getString("proxy", "")
|
||||
|
|
@ -626,7 +631,16 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
var urls = "";
|
||||
if(jsonObject.has("urls")) urls = jsonObject.getString("urls");
|
||||
if(jsonObject.has("requested_formats")) {
|
||||
val requestedFormats = jsonObject.getJSONArray("requested_formats")
|
||||
val urlList = mutableListOf<String>()
|
||||
val length = requestedFormats.length()-1
|
||||
for (i in length downTo 0) {
|
||||
urlList.add(requestedFormats.getJSONObject(i).getString("url"))
|
||||
}
|
||||
|
||||
urls = urlList.joinToString("\n")
|
||||
}
|
||||
|
||||
items.add(ResultItem(0,
|
||||
url,
|
||||
|
|
@ -927,7 +941,7 @@ class InfoUtil(private val context: Context) {
|
|||
if(downloadItem.type != DownloadViewModel.Type.command){
|
||||
if (downloadItem.SaveThumb) {
|
||||
request.addOption("--write-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "png")
|
||||
request.addOption("--convert-thumbnails", "jpg")
|
||||
}
|
||||
if (!sharedPreferences.getBoolean("mtime", false)){
|
||||
request.addOption("--no-mtime")
|
||||
|
|
@ -991,6 +1005,10 @@ class InfoUtil(private val context: Context) {
|
|||
conf.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
if (sharedPreferences.getBoolean("write_description", false)){
|
||||
request.addOption("--write-description")
|
||||
}
|
||||
}
|
||||
|
||||
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
|
||||
|
|
@ -1041,7 +1059,7 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
if (downloadItem.audioPreferences.embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "jpg")
|
||||
if (! request.hasOption("--convert-thumbnails")) 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")
|
||||
|
|
@ -1132,6 +1150,7 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||
request.addOption("--split-chapters")
|
||||
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
||||
}else{
|
||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import android.text.TextWatcher
|
|||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
|
|
@ -31,6 +32,8 @@ import androidx.core.content.FileProvider
|
|||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
|
|
@ -45,10 +48,12 @@ import com.google.android.material.datepicker.CalendarConstraints
|
|||
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.materialswitch.MaterialSwitch
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.Calendar
|
||||
|
|
@ -100,6 +105,7 @@ object UiUtil {
|
|||
val ok : Button = bottomSheet.findViewById(R.id.template_create)!!
|
||||
val title : TextInputLayout = bottomSheet.findViewById(R.id.title)!!
|
||||
val content : TextInputLayout = bottomSheet.findViewById(R.id.content)!!
|
||||
val extraCommandsSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extra_command_switch)!!
|
||||
val shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!!
|
||||
val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!!
|
||||
|
||||
|
|
@ -148,6 +154,8 @@ object UiUtil {
|
|||
}
|
||||
}
|
||||
|
||||
extraCommandsSwitch.isChecked = item!!.useAsExtraCommand
|
||||
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
||||
shortcutsChipGroup.removeAllViews()
|
||||
it.forEach {shortcut ->
|
||||
|
|
@ -166,7 +174,7 @@ object UiUtil {
|
|||
|
||||
ok.setOnClickListener {
|
||||
if (item == null){
|
||||
val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString())
|
||||
val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString(), extraCommandsSwitch.isChecked)
|
||||
commandTemplateViewModel.insert(t)
|
||||
newTemplate(t)
|
||||
}else{
|
||||
|
|
@ -507,4 +515,48 @@ object UiUtil {
|
|||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun showShortcuts(activity: Activity, commandTemplateViewModel: CommandTemplateViewModel, itemSelected: (itemSelected: String) -> Unit){
|
||||
val bottomSheet = BottomSheetDialog(activity)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.template_shortcuts_list)
|
||||
|
||||
val chipGroup = bottomSheet.findViewById<ChipGroup>(R.id.shortcutsChipGroup)
|
||||
val shortcutList = withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.getAllShortcuts()
|
||||
}
|
||||
|
||||
chipGroup!!.removeAllViews()
|
||||
shortcutList.forEach {shortcut ->
|
||||
val chip = activity.layoutInflater.inflate(R.layout.suggestion_chip, chipGroup, false) as Chip
|
||||
chip.text = shortcut.content
|
||||
chip.setOnClickListener {
|
||||
itemSelected(shortcut.content)
|
||||
}
|
||||
chipGroup.addView(chip)
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
fun RecyclerView.forceFastScrollMode()
|
||||
{
|
||||
overScrollMode = View.OVER_SCROLL_ALWAYS
|
||||
scrollBarStyle = View.SCROLLBARS_INSIDE_INSET
|
||||
isVerticalScrollBarEnabled = true
|
||||
setOnTouchListener { view, event ->
|
||||
if (event.x >= this.width - 30) {
|
||||
view.parent.requestDisallowInterceptTouchEvent(true)
|
||||
when (event.action and MotionEvent.ACTION_MASK) {
|
||||
MotionEvent.ACTION_UP -> view.parent.requestDisallowInterceptTouchEvent(false)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,8 +39,7 @@ class DownloadWorker(
|
|||
) : Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
itemId = inputData.getLong("id", 0)
|
||||
if (itemId == 0L) return Result.failure()
|
||||
|
||||
if (itemId == 0L || isStopped) return Result.failure()
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val infoUtil = InfoUtil(context)
|
||||
|
|
@ -74,6 +73,7 @@ class DownloadWorker(
|
|||
Log.e(TAG, downloadItem.toString())
|
||||
|
||||
runBlocking{
|
||||
YoutubeDL.getInstance().destroyProcessById(itemId.toString())
|
||||
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
|
||||
}
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
|
@ -118,7 +118,7 @@ class DownloadWorker(
|
|||
}
|
||||
runCatching {
|
||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||
setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line.chunked(5000).first().toString(), "id" to downloadItem.id, "log" to logDownloads))
|
||||
setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line.chunked(5000).first().toString(), "id" to downloadItem.id))
|
||||
val title: String = downloadItem.title
|
||||
notificationUtil.updateDownloadNotification(
|
||||
downloadItem.id.toInt(),
|
||||
|
|
@ -137,16 +137,16 @@ class DownloadWorker(
|
|||
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))
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id))
|
||||
try {
|
||||
finalPaths = withContext(Dispatchers.IO){
|
||||
FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id))
|
||||
}
|
||||
}
|
||||
|
||||
if (finalPaths.isNotEmpty()){
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id))
|
||||
}else{
|
||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ class DownloadWorker(
|
|||
|
||||
if (wasQuickDownloaded){
|
||||
runCatching {
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false))
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id))
|
||||
runBlocking {
|
||||
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
|
||||
if (res != null) {
|
||||
|
|
@ -242,7 +242,8 @@ class DownloadWorker(
|
|||
var wasQuickDownloaded = false
|
||||
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
|
||||
runCatching {
|
||||
setProgressAsync(workDataOf("progress" to 0, "output" to context.getString(R.string.updating_download_data), "id" to downloadItem.id, "log" to false))
|
||||
if (isStopped) destroyYTDLProcess()
|
||||
setProgressAsync(workDataOf("progress" to 0, "output" to context.getString(R.string.updating_download_data), "id" to downloadItem.id))
|
||||
val info = infoUtil.getMissingInfo(downloadItem.url)
|
||||
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
|
||||
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
|
||||
|
|
@ -259,10 +260,14 @@ class DownloadWorker(
|
|||
}
|
||||
|
||||
override fun onStopped() {
|
||||
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
|
||||
destroyYTDLProcess()
|
||||
super.onStopped()
|
||||
}
|
||||
|
||||
private fun destroyYTDLProcess(){
|
||||
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
|
||||
}
|
||||
|
||||
companion object {
|
||||
var itemId: Long = 0
|
||||
const val TAG = "DownloadWorker"
|
||||
|
|
|
|||
5
app/src/main/res/drawable/baseline_description_24.xml
Normal file
5
app/src/main/res/drawable/baseline_description_24.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:colorAccent" android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
|
||||
</vector>
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
<?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 xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?android:colorAccent"/>
|
||||
<size
|
||||
android:width="40dp"
|
||||
android:height="20dp"/>
|
||||
<corners
|
||||
android:topLeftRadius="20dp"
|
||||
android:topRightRadius="20dp"/>
|
||||
</shape>
|
||||
<corners
|
||||
android:radius="50dp" />
|
||||
|
||||
</rotate>
|
||||
<padding
|
||||
android:paddingLeft="22dp"
|
||||
android:paddingRight="22dp" />
|
||||
|
||||
<solid android:color="?android:colorAccent" />
|
||||
|
||||
</shape>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/command_template_item_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -31,24 +32,26 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
|
||||
<!-- <View-->
|
||||
<!-- android:id="@+id/divider"-->
|
||||
<!-- style="@style/Divider.Vertical"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toStartOf="@+id/check"-->
|
||||
<!-- app:layout_constraintStart_toEndOf="@+id/title"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||
|
||||
<!-- <RadioButton-->
|
||||
<!-- android:id="@+id/check"-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:gravity="center"-->
|
||||
<!-- android:minWidth="0dp"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- app:layout_constraintVertical_bias="0.558" />-->
|
||||
<TextView
|
||||
android:id="@+id/useInExtraCommands"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_corner"
|
||||
android:backgroundTint="?attr/colorSecondary"
|
||||
android:clickable="false"
|
||||
android:visibility="gone"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/extra_command"
|
||||
android:gravity="center"
|
||||
android:maxLength="17"
|
||||
android:maxLines="1"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/content" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -102,6 +102,18 @@
|
|||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/extra_command_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:checked="false"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:textSize="15sp"
|
||||
android:text="@string/extra_command"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
|
||||
<View
|
||||
style="@style/Divider.Horizontal"
|
||||
android:layout_marginVertical="10dp" />
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/from_textinput"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="80dp"
|
||||
android:layout_width="90dp"
|
||||
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="80dp"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/end"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
|||
|
|
@ -1,90 +1,147 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent"
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/use_extra_commands"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/current"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginVertical="10dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/use_extra_commands"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linear"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/currentTitle"
|
||||
android:layout_width="wrap_content"
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/current"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/current"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/currentText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/currentTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/current"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/currentText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</ScrollView>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/textInputLayout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/current">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/command"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textMultiLine"
|
||||
android:fontFamily="monospace"
|
||||
android:inputType="textMultiLine"
|
||||
android:maxLines="2000" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/okButton"
|
||||
android:layout_marginVertical="10dp"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/shortcuts"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_shortcut"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/okButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/commands"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/commands"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_terminal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/okButton"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:layout_margin="20dp"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
|
||||
|
||||
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -1,25 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="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"
|
||||
android:visibility="visible"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="30dp"
|
||||
android:layout_gravity="end"
|
||||
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" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recyclerview"
|
||||
|
|
@ -27,6 +25,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
|
|
@ -38,4 +37,4 @@
|
|||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -31,13 +31,25 @@
|
|||
android:orientation="vertical"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/use_cookies"
|
||||
android:layout_width="match_parent"
|
||||
android:background="?attr/colorSurfaceContainer"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:layout_height="70dp"
|
||||
android:checked="false"
|
||||
android:text="@string/use_cookies"/>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/newCookie"
|
||||
android:layout_margin="10dp"
|
||||
style="@style/Widget.Material3.Chip.Assist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/use_cookies"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:text="@string/new_cookie"
|
||||
app:chipIcon="@drawable/ic_plus" />
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="200dp"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
android:id="@+id/recyclerviewhistorys"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="vertical"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollEnabled="true"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
|
|
|
|||
|
|
@ -120,33 +120,6 @@
|
|||
|
||||
</com.google.android.material.search.SearchView>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/home_appbarlayout"
|
||||
app:liftOnScroll="true"
|
||||
android:background="@null"
|
||||
android:elevation="0dp"
|
||||
app:elevation="0dp"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/home_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
app:title="@string/app_name"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.search.SearchBar
|
||||
android:id="@+id/search_bar"
|
||||
app:menu="@menu/main_menu"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/search_hint" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -200,6 +173,30 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/home_appbarlayout"
|
||||
android:background="@null"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/home_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
app:title="@string/app_name"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.search.SearchBar
|
||||
android:id="@+id/search_bar"
|
||||
app:menu="@menu/main_menu"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/search_hint" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/home_fabs"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="100dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="100dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:fastScrollEnabled="true"
|
||||
android:scrollbars="none"
|
||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||
|
|
@ -36,4 +38,4 @@
|
|||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -80,7 +80,6 @@
|
|||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
|
|
@ -113,8 +112,7 @@
|
|||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
@ -124,7 +122,7 @@
|
|||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
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">
|
||||
|
||||
|
|
|
|||
14
app/src/main/res/menu/extra_commands_menu.xml
Normal file
14
app/src/main/res/menu/extra_commands_menu.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:theme="@style/BaseTheme">
|
||||
|
||||
<item android:title="@string/command_templates"
|
||||
android:icon="@drawable/ic_terminal"
|
||||
app:showAsAction="ifRoom"
|
||||
android:id="@+id/command_templates"/>
|
||||
<item android:title="@string/shortcuts"
|
||||
android:icon="@drawable/ic_shortcut"
|
||||
app:showAsAction="ifRoom"
|
||||
android:id="@+id/shortcuts"/>
|
||||
</menu>
|
||||
|
|
@ -272,10 +272,8 @@
|
|||
<string name="custom_audio_quality">استخدام جودة صوت مخصصة</string>
|
||||
<string name="piped_instance">مثيل Piped</string>
|
||||
<string name="piped_instance_summary">إدخال خادم PIPED API، يمكن للتطبيق استخدامه لاستعلامات وتنسيقات يوتيوب</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>
|
||||
<string name="clear_saved">تنظيف المحفوظة</string>
|
||||
<string name="save_for_later">حفظ، للتحميل فيما بعد؟</string>
|
||||
|
|
|
|||
|
|
@ -275,10 +275,8 @@
|
|||
<string name="retries">Wiederholungen</string>
|
||||
<string name="fragment_retries">Fragmentwiederholungen</string>
|
||||
<string name="format_order">Formatreihenfolge</string>
|
||||
<string name="subtitle_format">Untertitelformat
|
||||
\n</string>
|
||||
<string name="subtitle_format">Untertitelformat</string>
|
||||
<string name="hide_thumbnails">Vorschaubilder verstecken</string>
|
||||
<string name="hide_terminal">Terminal im Freigabemenü ausblenden</string>
|
||||
<string name="saved">Gespeichert</string>
|
||||
<string name="save_for_later">Download für später merken\?</string>
|
||||
<string name="clear_saved">Gespeichertes leeren</string>
|
||||
|
|
|
|||
|
|
@ -281,10 +281,8 @@
|
|||
<string name="use_extra_commands_summary">Do pobierania audio/wideo. Dodaj dodatkowe polecenia wraz z konfiguracją GUI</string>
|
||||
<string name="current">Bieżące polecenie</string>
|
||||
<string name="hide_thumbnails">Ukryj miniatury</string>
|
||||
<string name="hide_terminal">Ukryj terminal w menu udostępniania</string>
|
||||
<string name="saved">Zapisane</string>
|
||||
<string name="clear_saved">Wyczyść zapisane</string>
|
||||
<string name="save_for_later">Zachować pobieranie na później\?</string>
|
||||
<string name="subtitle_format">Format napisów
|
||||
\n</string>
|
||||
<string name="subtitle_format">Format napisów</string>
|
||||
</resources>
|
||||
|
|
@ -279,7 +279,6 @@
|
|||
<string name="force_keyframes_summary">Processo mais lento, mas cortes mais precisos</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>
|
||||
<string name="clear_saved">Remoção Concluída</string>
|
||||
<string name="save_for_later">Salvar download para mais tarde\?</string>
|
||||
|
|
|
|||
|
|
@ -281,10 +281,8 @@
|
|||
<string name="saved">Guardado</string>
|
||||
<string name="clear_saved">Limpar guardado</string>
|
||||
<string name="use_extra_commands_summary">Para transferências de áudio/vídeo. Adicionar comandos extra juntamente com a configuração GUI</string>
|
||||
<string name="subtitle_format">Formato da legenda
|
||||
\n</string>
|
||||
<string name="subtitle_format">Formato da legenda</string>
|
||||
<string name="hide_thumbnails">Esconder miniaturas</string>
|
||||
<string name="hide_terminal">Ocultar o Terminal do menu de partilha</string>
|
||||
<string name="force_keyframes_summary">Processo mais lento, mas cortes mais precisos</string>
|
||||
<string name="save_for_later">Guardar a transferência para mais tarde\?</string>
|
||||
<string name="force_keyframes">Forçar quadros-chave nos cortes</string>
|
||||
|
|
|
|||
|
|
@ -282,7 +282,6 @@
|
|||
<string name="current">Текущая команда</string>
|
||||
<string name="subtitle_format">Формат субтитров</string>
|
||||
<string name="hide_thumbnails">Скрыть миниатюры</string>
|
||||
<string name="hide_terminal">Скрыть терминал из меню «Поделиться»</string>
|
||||
<string name="saved">Сохранено</string>
|
||||
<string name="clear_saved">Очистить сохраненное</string>
|
||||
<string name="save_for_later">Сохранить загрузку на потом\?</string>
|
||||
|
|
|
|||
|
|
@ -98,10 +98,8 @@
|
|||
<string name="save_for_later">บันทึกการดาวน์โหลดสำหรับภายหลัง\?</string>
|
||||
<string name="clear_saved">ล้างข้อมูลที่บันทึกไว้</string>
|
||||
<string name="saved">บันทึกแล้ว</string>
|
||||
<string name="hide_terminal">ซ่อน Terminal จากเมนูแชร์</string>
|
||||
<string name="hide_thumbnails">ซ่อนภาพขนาดย่อ</string>
|
||||
<string name="subtitle_format">รูปแบบคำบรรยาย
|
||||
\n</string>
|
||||
<string name="subtitle_format">รูปแบบคำบรรยาย</string>
|
||||
<string name="current">คำสั่งปัจจุบัน</string>
|
||||
<string name="use_extra_commands">เพิ่มคำสั่งพิเศษ</string>
|
||||
<string name="force_keyframes_summary">กระบวนการช้าลง แต่มีการตัดที่แม่นยำยิ่งขึ้น</string>
|
||||
|
|
|
|||
|
|
@ -286,10 +286,8 @@
|
|||
<string name="use_extra_commands_summary">Ses / Video indirmeleri için. GUI yapılandırması ile birlikte ekstra komutlar ekleyin</string>
|
||||
<string name="current">Geçerli Komut</string>
|
||||
<string name="save_for_later">Daha Sonra İndirmek için Kaydedilsin mi\?</string>
|
||||
<string name="subtitle_format">Altyazı Biçimi
|
||||
\n</string>
|
||||
<string name="subtitle_format">Altyazı Biçimi</string>
|
||||
<string name="saved">Kaydedildi</string>
|
||||
<string name="clear_saved">Kaydedilenleri Temizle</string>
|
||||
<string name="hide_terminal">Terminal\'i paylaş menüsünden gizle</string>
|
||||
<string name="hide_thumbnails">Küçük Resimleri Gizle</string>
|
||||
</resources>
|
||||
|
|
@ -281,11 +281,9 @@
|
|||
<string name="current">Поточна команда</string>
|
||||
<string name="use_extra_commands_summary">Додайте свої додаткові команди перед завантаженням аудіо/відео</string>
|
||||
<string name="hide_thumbnails">Приховати мініатюри</string>
|
||||
<string name="hide_terminal">Приховати термінал у меню спільного доступу</string>
|
||||
<string name="saved">Збережено</string>
|
||||
<string name="clear_saved">Очистити збережене</string>
|
||||
<string name="subtitle_format">Формат субтитрів
|
||||
\n</string>
|
||||
<string name="subtitle_format">Формат субтитрів</string>
|
||||
<string name="save_for_later">Зберегти завантаження на потім\?</string>
|
||||
<string name="orange">Помаранчевий</string>
|
||||
</resources>
|
||||
|
|
@ -278,10 +278,8 @@
|
|||
<string name="use_extra_commands">新增額外指令</string>
|
||||
<string name="use_extra_commands_summary">為了音訊 / 影片下載,請在圖形使用者介面配置中新增額外的指令</string>
|
||||
<string name="hide_thumbnails">隱藏縮略圖</string>
|
||||
<string name="subtitle_format">字幕格式
|
||||
\n</string>
|
||||
<string name="subtitle_format">字幕格式</string>
|
||||
<string name="force_keyframes_summary">較為緩慢的處理過程,但能得到更準確的剪輯結果</string>
|
||||
<string name="hide_terminal">隱藏分享選單中的終端機</string>
|
||||
<string name="saved">已儲存</string>
|
||||
<string name="clear_saved">清除已儲存的內容</string>
|
||||
<string name="save_for_later">儲存下載以供日後使用?</string>
|
||||
|
|
|
|||
|
|
@ -294,4 +294,8 @@
|
|||
<string name="saved">Saved</string>
|
||||
<string name="clear_saved">Clear Saved</string>
|
||||
<string name="save_for_later">Save Download for Later?</string>
|
||||
<string name="write_description">Save Description</string>
|
||||
<string name="write_description_summary">Write description file</string>
|
||||
<string name="extra_command">Extra Command</string>
|
||||
<string name="use_cookies">Use Cookies</string>
|
||||
</resources>
|
||||
|
|
@ -53,6 +53,14 @@
|
|||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/subtitle_format" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/baseline_description_24"
|
||||
app:key="write_description"
|
||||
android:summary="@string/write_description_summary"
|
||||
app:title="@string/write_description" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ buildscript {
|
|||
coroutineVer = "1.6.4"
|
||||
retrofitVer = "2.9.0"
|
||||
kodeinVer = "7.16.0"
|
||||
navVer = "2.5.3"
|
||||
navVer = "2.6.0"
|
||||
media3_version = "1.1.0"
|
||||
}
|
||||
repositories {
|
||||
|
|
|
|||
Loading…
Reference in a new issue