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 versionMajor = 1
|
||||||
def versionMinor = 6
|
def versionMinor = 6
|
||||||
def versionPatch = 3
|
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 = ""
|
def versionExt = ""
|
||||||
|
|
||||||
if (versionBuild > 0){
|
if (versionBuild > 0){
|
||||||
|
|
@ -152,18 +152,13 @@ dependencies {
|
||||||
implementation 'androidx.preference:preference:1.2.0'
|
implementation 'androidx.preference:preference:1.2.0'
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$navVer"
|
implementation "androidx.navigation:navigation-fragment-ktx:$navVer"
|
||||||
implementation "androidx.navigation:navigation-ui-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.test.ext:junit-ktx:1.1.5'
|
||||||
implementation 'androidx.benchmark:benchmark-macro:1.1.1'
|
implementation 'androidx.benchmark:benchmark-macro:1.1.1'
|
||||||
testImplementation "junit:junit:$junitVer"
|
testImplementation "junit:junit:$junitVer"
|
||||||
androidTestImplementation "junit:junit:$junitVer"
|
androidTestImplementation "junit:junit:$junitVer"
|
||||||
androidTestImplementation "androidx.test.ext:junit:$androidJunitVer"
|
androidTestImplementation "androidx.test.ext:junit:$androidJunitVer"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVer"
|
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 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
implementation "com.devbrackets.android:exomedia:4.3.0"
|
implementation "com.devbrackets.android:exomedia:4.3.0"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 9,
|
"version": 9,
|
||||||
"identityHash": "bcd20f64b54fbc6e470be0d15059a66e",
|
"identityHash": "d29e09789b7c96b5551b80da253b7330",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "results",
|
"tableName": "results",
|
||||||
|
|
@ -180,7 +180,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "downloads",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
|
@ -324,12 +324,6 @@
|
||||||
"columnName": "logID",
|
"columnName": "logID",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "workID",
|
|
||||||
"columnName": "workID",
|
|
||||||
"affinity": "BLOB",
|
|
||||||
"notNull": false
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
|
@ -343,7 +337,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "commandTemplates",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
|
@ -362,6 +356,13 @@
|
||||||
"columnName": "content",
|
"columnName": "content",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "useAsExtraCommand",
|
||||||
|
"columnName": "useAsExtraCommand",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
|
@ -511,7 +512,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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
|
package com.deniscerri.ytdlnis
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.os.Looper
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
|
@ -66,7 +67,9 @@ class App : Application() {
|
||||||
)
|
)
|
||||||
|
|
||||||
}catch (e: Exception){
|
}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()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.navOptions
|
import androidx.navigation.navOptions
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
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.navigation.NavigationView
|
||||||
import com.google.android.material.navigationrail.NavigationRailView
|
import com.google.android.material.navigationrail.NavigationRailView
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
|
|
@ -116,14 +120,14 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
// val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
||||||
graph.setStartDestination(R.id.homeFragment)
|
// graph.setStartDestination(R.id.homeFragment)
|
||||||
when(sharedPreferences.getString("start_destination", "")) {
|
// when(sharedPreferences.getString("start_destination", "")) {
|
||||||
"History" -> graph.setStartDestination(R.id.historyFragment)
|
// "History" -> graph.setStartDestination(R.id.historyFragment)
|
||||||
"More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
// "More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
navController.graph = graph
|
// navController.graph = graph
|
||||||
|
|
||||||
if (navigationView is NavigationBarView){
|
if (navigationView is NavigationBarView){
|
||||||
(navigationView as NavigationBarView).setupWithNavController(navController)
|
(navigationView as NavigationBarView).setupWithNavController(navController)
|
||||||
|
|
@ -172,11 +176,24 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
terminateDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
terminateDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
terminateDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
terminateDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
if (doNotShowAgain){
|
runBlocking {
|
||||||
sharedPreferences.edit().putBoolean("ask_terminate_app", false).apply()
|
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()
|
terminateDialog.show()
|
||||||
}else{
|
}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) {
|
private fun View.visibilityChanged(action: (View) -> Unit) {
|
||||||
this.viewTreeObserver.addOnGlobalLayoutListener {
|
this.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
|
|
|
||||||
|
|
@ -148,16 +148,10 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
pauseButton.setOnClickListener {
|
pauseButton.setOnClickListener {
|
||||||
if (pauseButton.tag == ActiveDownloadAction.Pause){
|
if (pauseButton.tag == ActiveDownloadAction.Pause){
|
||||||
onItemClickListener.onPauseClick(item.id, 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{
|
}else{
|
||||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Resume)
|
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
|
package com.deniscerri.ytdlnis.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.opengl.Visibility
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
@ -46,18 +47,16 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
||||||
val content = card.findViewById<TextView>(R.id.content)
|
val content = card.findViewById<TextView>(R.id.content)
|
||||||
content.text = item?.content
|
content.text = item?.content
|
||||||
|
|
||||||
// val check = card.findViewById<Button>(R.id.check)
|
val useInExtraCommands = card.findViewById<TextView>(R.id.useInExtraCommands)
|
||||||
//
|
if (item!!.useAsExtraCommand) useInExtraCommands.visibility = View.VISIBLE
|
||||||
// check.setOnClickListener {
|
else useInExtraCommands.visibility = View.GONE
|
||||||
// onItemClickListener.onSelected(item!!)
|
|
||||||
// }
|
|
||||||
|
|
||||||
card.setOnClickListener {
|
card.setOnClickListener {
|
||||||
onItemClickListener.onItemClick(item!!, position)
|
onItemClickListener.onItemClick(item, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
card.setOnLongClickListener {
|
card.setOnLongClickListener {
|
||||||
onItemClickListener.onDelete(item!!); true
|
onItemClickListener.onDelete(item); true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.deniscerri.ytdlnis.database.models.*
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
@Database(
|
@Database(
|
||||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class, LogItem::class],
|
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class, LogItem::class],
|
||||||
version = 8,
|
version = 9,
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
AutoMigration (from = 1, to = 2),
|
AutoMigration (from = 1, to = 2),
|
||||||
AutoMigration (from = 2, to = 3),
|
AutoMigration (from = 2, to = 3),
|
||||||
|
|
@ -16,7 +16,8 @@ import com.deniscerri.ytdlnis.database.models.*
|
||||||
AutoMigration (from = 4, to = 5),
|
AutoMigration (from = 4, to = 5),
|
||||||
AutoMigration (from = 5, to = 6),
|
AutoMigration (from = 5, to = 6),
|
||||||
AutoMigration (from = 6, to = 7),
|
AutoMigration (from = 6, to = 7),
|
||||||
AutoMigration (from = 7, to = 8)
|
AutoMigration (from = 7, to = 8),
|
||||||
|
AutoMigration (from = 8, to = 9)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
abstract class DBManager : RoomDatabase(){
|
abstract class DBManager : RoomDatabase(){
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ interface CommandTemplateDao {
|
||||||
|
|
||||||
@Query("SELECT * FROM commandTemplates ORDER BY id DESC")
|
@Query("SELECT * FROM commandTemplates ORDER BY id DESC")
|
||||||
fun getAllTemplatesFlow() : Flow<List<CommandTemplate>>
|
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")
|
@Query("SELECT * FROM templateShortcuts ORDER BY id DESC")
|
||||||
fun getAllShortcutsFlow() : Flow<List<TemplateShortcut>>
|
fun getAllShortcutsFlow() : Flow<List<TemplateShortcut>>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.models
|
package com.deniscerri.ytdlnis.database.models
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
@ -10,5 +11,7 @@ data class CommandTemplate(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long,
|
var id: Long,
|
||||||
var title: String,
|
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(
|
data class ResultItem(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long,
|
var id: Long,
|
||||||
val url: String,
|
var url: String,
|
||||||
var title: String,
|
var title: String,
|
||||||
var author: String,
|
var author: String,
|
||||||
val duration: 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?>{
|
suspend fun getOne(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?>{
|
||||||
val infoUtil = InfoUtil(context)
|
val infoUtil = InfoUtil(context)
|
||||||
try {
|
try {
|
||||||
val v = infoUtil.getVideo(inputQuery)
|
val v = infoUtil.getYoutubeVideo(inputQuery)
|
||||||
if (resetResults) {
|
if (resetResults) {
|
||||||
deleteAll()
|
deleteAll()
|
||||||
itemCount.value = v.size
|
itemCount.value = v.size
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import android.content.res.Resources
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
|
@ -18,8 +19,10 @@ import androidx.work.Constraints
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.NetworkType
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkRequest
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import com.deniscerri.ytdlnis.App
|
import com.deniscerri.ytdlnis.App
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
|
@ -42,8 +45,11 @@ import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
@ -71,6 +77,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
private val formatIDPreference: List<String>
|
private val formatIDPreference: List<String>
|
||||||
private val audioFormatIDPreference: List<String>
|
private val audioFormatIDPreference: List<String>
|
||||||
private val resources : Resources
|
private val resources : Resources
|
||||||
|
private var extraCommands: String = ""
|
||||||
enum class Type {
|
enum class Type {
|
||||||
audio, video, command
|
audio, video, command
|
||||||
}
|
}
|
||||||
|
|
@ -90,6 +97,11 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
savedDownloads = repository.savedDownloads.asLiveData()
|
savedDownloads = repository.savedDownloads.asLiveData()
|
||||||
cancelledDownloads = repository.cancelledDownloads.asLiveData()
|
cancelledDownloads = repository.cancelledDownloads.asLiveData()
|
||||||
erroredDownloads = repository.erroredDownloads.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()
|
videoQualityPreference = sharedPreferences.getString("video_quality", application.getString(R.string.best_quality)).toString()
|
||||||
formatIDPreference = sharedPreferences.getString("format_id", "").toString().split(",")
|
formatIDPreference = sharedPreferences.getString("format_id", "").toString().split(",")
|
||||||
|
|
@ -190,7 +202,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
container!!,
|
container!!,
|
||||||
"",
|
"",
|
||||||
resultItem.formats,
|
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,
|
container,
|
||||||
"",
|
"",
|
||||||
ArrayList(),
|
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)
|
repository.insert(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun insertAll(items: List<DownloadItem>)= viewModelScope.launch(Dispatchers.IO){
|
||||||
|
items.forEach{
|
||||||
|
repository.insert(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteCancelled() = viewModelScope.launch(Dispatchers.IO) {
|
fun deleteCancelled() = viewModelScope.launch(Dispatchers.IO) {
|
||||||
repository.deleteCancelled()
|
repository.deleteCancelled()
|
||||||
}
|
}
|
||||||
|
|
@ -473,10 +491,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
exists = true
|
exists = true
|
||||||
}else{
|
}else{
|
||||||
if (it.id == 0L){
|
if (it.id == 0L){
|
||||||
val insert = async {repository.insert(it)}
|
val id = runBlocking {repository.insert(it)}
|
||||||
val id = insert.await()
|
|
||||||
it.id = id
|
it.id = id
|
||||||
}else{
|
}else if (it.status == DownloadRepository.Status.Queued.toString()){
|
||||||
repository.update(it)
|
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()
|
Toast.makeText(context, context.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queuedItems.forEach {
|
queuedItems.forEach {
|
||||||
val currentTime = System.currentTimeMillis()
|
val currentTime = System.currentTimeMillis()
|
||||||
var delay = if (it.downloadStartTime != 0L){
|
var delay = if (it.downloadStartTime != 0L){
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ class ShareActivity : BaseActivity() {
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
private var quickDownload by Delegates.notNull<Boolean>()
|
private var quickDownload by Delegates.notNull<Boolean>()
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
finishAndRemoveTask()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
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.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Range
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -58,7 +59,7 @@ import java.util.concurrent.Executors
|
||||||
import kotlin.properties.Delegates
|
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 behavior: BottomSheetBehavior<View>
|
||||||
private lateinit var infoUtil: InfoUtil
|
private lateinit var infoUtil: InfoUtil
|
||||||
private lateinit var player: ExoPlayer
|
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 var timeSeconds by Delegates.notNull<Int>()
|
||||||
private lateinit var selectedCuts: MutableList<String>
|
private lateinit var selectedCuts: MutableList<String>
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||||
|
|
@ -157,12 +157,12 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
||||||
if (urls.isNullOrEmpty()) {
|
if (urls.isNullOrEmpty()) {
|
||||||
infoUtil.getStreamingUrlAndChapters(item.url)
|
infoUtil.getStreamingUrlAndChapters(item.url)
|
||||||
}else {
|
}else {
|
||||||
urls.split("\n").toMutableList()
|
urls!!.split("\n").toMutableList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.isEmpty()) throw Exception("No Data found!")
|
if (data.isEmpty()) throw Exception("No Data found!")
|
||||||
if (chapters!!.isEmpty()){
|
if (chapters!!.isEmpty() && urls!!.isBlank()){
|
||||||
try{
|
try{
|
||||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||||
chapters = Gson().fromJson(data.first().toString(), listType)
|
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")
|
fromTextInput.editText!!.setText("0:00")
|
||||||
toTextInput.editText!!.setText(item.duration)
|
toTextInput.editText!!.setText(item.duration)
|
||||||
|
|
||||||
rangeSlider.addOnChangeListener { rangeSlider, _, _ ->
|
rangeSlider.addOnSliderTouchListener(object : RangeSlider.OnSliderTouchListener {
|
||||||
val values = rangeSlider.values
|
override fun onStartTrackingTouch(slider: RangeSlider) {
|
||||||
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)
|
override fun onStopTrackingTouch(slider: RangeSlider) {
|
||||||
toTextInput.editText!!.setText(endTimestampString)
|
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 {
|
try {
|
||||||
player.seekTo((startTimestamp * 1000).toLong())
|
player.seekTo((startTimestamp * 1000).toLong())
|
||||||
player.play()
|
player.play()
|
||||||
}catch (ignored: Exception) {}
|
}catch (ignored: Exception) {}
|
||||||
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
fromTextInput.editText!!.setOnKeyListener(object : View.OnKeyListener {
|
fromTextInput.editText!!.setOnKeyListener(object : View.OnKeyListener {
|
||||||
|
|
||||||
|
|
@ -271,20 +276,23 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
||||||
|
|
||||||
fromTextInput.editText!!.clearFocus()
|
fromTextInput.editText!!.clearFocus()
|
||||||
val seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
val seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||||
if (seconds == 0) {
|
val endSeconds = convertStringToTimestamp(toTextInput.editText!!.text.toString())
|
||||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
val startValue = (seconds.toFloat() / endTimestamp) * 100
|
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))
|
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rangeSlider.setValues(startValue, rangeSlider.valueTo)
|
rangeSlider.setValues(startValue, endValue)
|
||||||
val startValueTimeStampSeconds = (startValue.toInt() * timeSeconds) / 100
|
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||||
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startValueTimeStampSeconds, Locale.US))
|
try {
|
||||||
|
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||||
|
player.play()
|
||||||
|
}catch (ignored: Exception) {}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -299,24 +307,28 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
||||||
if ((event!!.action == KeyEvent.ACTION_DOWN) &&
|
if ((event!!.action == KeyEvent.ACTION_DOWN) &&
|
||||||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
|
(keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||||
|
|
||||||
|
val values = rangeSlider.values
|
||||||
val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
||||||
|
|
||||||
toTextInput.editText!!.clearFocus()
|
toTextInput.editText!!.clearFocus()
|
||||||
|
val startSeconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||||
val seconds = convertStringToTimestamp(toTextInput.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) {
|
if (seconds == 0) {
|
||||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||||
return true
|
}else if (endValue > 100 || endValue <= rangeSlider.valueFrom.toInt()){
|
||||||
}
|
|
||||||
|
|
||||||
val endValue = (seconds.toFloat() / endTimestamp) * 100
|
|
||||||
if (endValue > 100 || endValue <= rangeSlider.valueFrom.toInt()){
|
|
||||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rangeSlider.setValues(rangeSlider.valueFrom, endValue)
|
rangeSlider.setValues(startValue, endValue)
|
||||||
val endValueTimeStampSeconds = (endValue.toInt() * timeSeconds) / 100
|
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||||
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endValueTimeStampSeconds, Locale.US))
|
try {
|
||||||
|
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||||
|
player.play()
|
||||||
|
}catch (ignored: Exception) {}
|
||||||
|
|
||||||
return true
|
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
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
|
import com.deniscerri.ytdlnis.databinding.ExtraCommandsBottomSheetBinding
|
||||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
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)){
|
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||||
extraCommands.visibility = View.VISIBLE
|
extraCommands.visibility = View.VISIBLE
|
||||||
extraCommands.setOnClickListener {
|
extraCommands.setOnClickListener {
|
||||||
val bottomSheet = BottomSheetDialog(requireContext())
|
val callback = object : ExtraCommandsListener {
|
||||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
override fun onChangeExtraCommand(c: String) {
|
||||||
bottomSheet.setContentView(R.layout.extra_commands_bottom_sheet)
|
downloadItem.extraCommands = c
|
||||||
|
}
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bottomSheet.show()
|
val bottomSheetDialog = AddExtraCommandsDialog(downloadItem, callback)
|
||||||
val displayMetrics = DisplayMetrics()
|
bottomSheetDialog.show(parentFragmentManager, "extraCommands")
|
||||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
|
||||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
|
||||||
bottomSheet.window!!.setLayout(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
extraCommands.visibility = View.GONE
|
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)
|
val editSelected : Chip = view.findViewById(R.id.editSelected)
|
||||||
editSelected.setOnClickListener {
|
editSelected.setOnClickListener {
|
||||||
var current = templates.find { it.title == autoCompleteTextView.text.toString() }
|
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) {
|
UiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||||
templates.add(it)
|
templates.add(it)
|
||||||
chosenCommandView.editText!!.setText(it.content)
|
chosenCommandView.editText!!.setText(it.content)
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
|
@ -145,10 +145,10 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
||||||
dd.setTitle(getString(R.string.save_for_later))
|
dd.setTitle(getString(R.string.save_for_later))
|
||||||
dd.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
dd.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
lifecycleScope.launch(Dispatchers.IO){
|
lifecycleScope.launch{
|
||||||
items.forEach {
|
items.map { it.status = DownloadRepository.Status.Saved.toString() }
|
||||||
it.status = DownloadRepository.Status.Saved.toString()
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.updateDownload(it)
|
downloadViewModel.insertAll(items)
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -408,37 +408,14 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
||||||
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||||
extraCommands.visibility = View.VISIBLE
|
extraCommands.visibility = View.VISIBLE
|
||||||
extraCommands.setOnClickListener {
|
extraCommands.setOnClickListener {
|
||||||
val bottomSheet = BottomSheetDialog(requireContext())
|
val callback = object : ExtraCommandsListener {
|
||||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
override fun onChangeExtraCommand(c: String) {
|
||||||
bottomSheet.setContentView(R.layout.extra_commands_bottom_sheet)
|
downloadItem.extraCommands = c
|
||||||
|
}
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bottomSheet.show()
|
val bottomSheetDialog = AddExtraCommandsDialog(downloadItem, callback)
|
||||||
val displayMetrics = DisplayMetrics()
|
bottomSheetDialog.show(parentFragmentManager, "extraCommands")
|
||||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
|
||||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
|
||||||
bottomSheet.window!!.setLayout(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
extraCommands.visibility = View.GONE
|
extraCommands.visibility = View.GONE
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,20 @@
|
||||||
package com.deniscerri.ytdlnis.ui.downloads
|
package com.deniscerri.ytdlnis.ui.downloads
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.OnClickListener
|
import android.view.View.OnClickListener
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.allViews
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
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.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||||
|
|
@ -62,45 +71,47 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
)
|
)
|
||||||
|
|
||||||
activeRecyclerView = view.findViewById(R.id.download_recyclerview)
|
activeRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
|
activeRecyclerView.forceFastScrollMode()
|
||||||
activeRecyclerView.adapter = activeDownloads
|
activeRecyclerView.adapter = activeDownloads
|
||||||
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
||||||
pauseResume = view.findViewById(R.id.pause_resume)
|
pauseResume = view.findViewById(R.id.pause_resume)
|
||||||
|
|
||||||
pauseResume.setOnClickListener {
|
pauseResume.setOnClickListener {
|
||||||
if (pauseResume.text == requireContext().getString(R.string.pause)){
|
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")
|
lifecycleScope.launch {
|
||||||
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
runBlocking {
|
||||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
val queued = withContext(Dispatchers.IO){
|
||||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
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{
|
}else{
|
||||||
val toQueue = list.filter { it.status == DownloadRepository.Status.Paused.toString() }
|
lifecycleScope.launch {
|
||||||
toQueue.forEach {
|
val toQueue = list.filter { it.status == DownloadRepository.Status.Paused.toString() }.toMutableList()
|
||||||
it.status = DownloadRepository.Status.Active.toString()
|
toQueue.forEach {
|
||||||
downloadViewModel.updateDownload(it)
|
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 queuedItems = withContext(Dispatchers.IO){
|
||||||
val pauseButton = card.findViewById<MaterialButton>(R.id.active_download_pause)
|
downloadViewModel.getQueued()
|
||||||
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_delete)
|
}
|
||||||
|
toQueue.addAll(queuedItems)
|
||||||
pauseButton.icon = ContextCompat.getDrawable(requireContext(), R.drawable.exomedia_ic_pause_white)
|
runBlocking {
|
||||||
progressBar.isIndeterminate = true
|
downloadViewModel.queueDownloads(toQueue)
|
||||||
cancelButton.visibility = View.GONE
|
}
|
||||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Pause
|
|
||||||
}
|
|
||||||
runBlocking {
|
|
||||||
downloadViewModel.queueDownloads(toQueue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +120,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
list = it
|
list = it
|
||||||
activeDownloads.submitList(it)
|
activeDownloads.submitList(it)
|
||||||
|
|
||||||
if (list.isNotEmpty()){
|
if (it.size > 1){
|
||||||
pauseResume.visibility = View.VISIBLE
|
pauseResume.visibility = View.VISIBLE
|
||||||
if (list.all { l -> l.status == DownloadRepository.Status.Paused.toString() }){
|
if (list.all { l -> l.status == DownloadRepository.Status.Paused.toString() }){
|
||||||
pauseResume.text = requireContext().getString(R.string.resume)
|
pauseResume.text = requireContext().getString(R.string.resume)
|
||||||
|
|
@ -117,6 +128,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
pauseResume.text = requireContext().getString(R.string.pause)
|
pauseResume.text = requireContext().getString(R.string.pause)
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
activeDownloads.notifyDataSetChanged()
|
||||||
pauseResume.visibility = View.GONE
|
pauseResume.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +143,6 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
|
|
||||||
val progress = work.progress.getInt("progress", 0)
|
val progress = work.progress.getInt("progress", 0)
|
||||||
val output = work.progress.getString("output")
|
val output = work.progress.getString("output")
|
||||||
val log = work.progress.getBoolean("log", false)
|
|
||||||
|
|
||||||
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
||||||
val outputText = view.findViewWithTag<TextView>("$id##output")
|
val outputText = view.findViewWithTag<TextView>("$id##output")
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
package com.deniscerri.ytdlnis.ui.downloads
|
package com.deniscerri.ytdlnis.ui.downloads
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
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.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
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.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
|
@ -75,6 +79,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
||||||
)
|
)
|
||||||
|
|
||||||
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
|
cancelledRecyclerView.forceFastScrollMode()
|
||||||
cancelledRecyclerView.adapter = cancelledDownloads
|
cancelledRecyclerView.adapter = cancelledDownloads
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
if (preferences.getBoolean("swipe_gestures", true)){
|
if (preferences.getBoolean("swipe_gestures", true)){
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ class DownloadQueueMainFragment : Fragment(){
|
||||||
when(m.itemId){
|
when(m.itemId){
|
||||||
R.id.clear_queue -> {
|
R.id.clear_queue -> {
|
||||||
showDeleteDialog {
|
showDeleteDialog {
|
||||||
downloadViewModel.cancelQueued()
|
cancelAllDownloads()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.clear_cancelled -> {
|
R.id.clear_cancelled -> {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.ui.downloads
|
package com.deniscerri.ytdlnis.ui.downloads
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
|
|
@ -9,6 +10,7 @@ import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
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.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
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.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
|
@ -75,6 +78,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
)
|
)
|
||||||
|
|
||||||
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
|
erroredRecyclerView.forceFastScrollMode()
|
||||||
erroredRecyclerView.adapter = erroredDownloads
|
erroredRecyclerView.adapter = erroredDownloads
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
if (preferences.getBoolean("swipe_gestures", true)){
|
if (preferences.getBoolean("swipe_gestures", true)){
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@ import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.EditText
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
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.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
|
@ -91,6 +95,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
||||||
)
|
)
|
||||||
|
|
||||||
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
|
queuedRecyclerView.forceFastScrollMode()
|
||||||
queuedRecyclerView.adapter = queuedDownloads
|
queuedRecyclerView.adapter = queuedDownloads
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
if (preferences.getBoolean("swipe_gestures", true)){
|
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
|
package com.deniscerri.ytdlnis.ui.downloads
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
|
|
@ -9,6 +10,7 @@ import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
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.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
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.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
|
@ -74,6 +77,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
||||||
)
|
)
|
||||||
|
|
||||||
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
|
savedRecyclerView.forceFastScrollMode()
|
||||||
savedRecyclerView.adapter = savedDownloads
|
savedRecyclerView.adapter = savedDownloads
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
if (preferences.getBoolean("swipe_gestures", true)){
|
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.Context.INPUT_METHOD_SERVICE
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
@ -14,6 +15,7 @@ import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
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.appbar.MaterialToolbar
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
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.snackbar.Snackbar
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||||
|
|
@ -42,22 +45,26 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
||||||
private lateinit var recyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
private lateinit var listAdapter: CookieAdapter
|
private lateinit var listAdapter: CookieAdapter
|
||||||
private lateinit var topAppBar: MaterialToolbar
|
private lateinit var topAppBar: MaterialToolbar
|
||||||
|
private lateinit var useCookies : MaterialSwitch
|
||||||
private lateinit var cookiesViewModel: CookieViewModel
|
private lateinit var cookiesViewModel: CookieViewModel
|
||||||
private lateinit var cookiesList: List<CookieItem>
|
private lateinit var cookiesList: List<CookieItem>
|
||||||
private lateinit var noResults : RelativeLayout
|
private lateinit var noResults : RelativeLayout
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
|
private lateinit var preferences: SharedPreferences
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
|
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
return inflater.inflate(R.layout.fragment_cookies, container, false)
|
return inflater.inflate(R.layout.fragment_cookies, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
topAppBar = view.findViewById(R.id.logs_toolbar)
|
topAppBar = view.findViewById(R.id.logs_toolbar)
|
||||||
|
useCookies = view.findViewById(R.id.use_cookies)
|
||||||
topAppBar.setNavigationOnClickListener { mainActivity.onBackPressedDispatcher.onBackPressed() }
|
topAppBar.setNavigationOnClickListener { mainActivity.onBackPressedDispatcher.onBackPressed() }
|
||||||
cookiesList = listOf()
|
cookiesList = listOf()
|
||||||
noResults = view.findViewById(R.id.no_results)
|
noResults = view.findViewById(R.id.no_results)
|
||||||
|
|
@ -67,6 +74,7 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
||||||
this,
|
this,
|
||||||
mainActivity
|
mainActivity
|
||||||
)
|
)
|
||||||
|
val newCookie = view.findViewById<Chip>(R.id.newCookie)
|
||||||
recyclerView = view.findViewById(R.id.template_recyclerview)
|
recyclerView = view.findViewById(R.id.template_recyclerview)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
recyclerView.adapter = listAdapter
|
recyclerView.adapter = listAdapter
|
||||||
|
|
@ -85,6 +93,16 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
||||||
}
|
}
|
||||||
initMenu()
|
initMenu()
|
||||||
initChips()
|
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() {
|
private fun initMenu() {
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,24 @@ import android.view.ViewGroup
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
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.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
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
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class MoreFragment : Fragment() {
|
class MoreFragment : Fragment() {
|
||||||
|
|
@ -29,12 +41,14 @@ class MoreFragment : Fragment() {
|
||||||
private lateinit var terminateApp: TextView
|
private lateinit var terminateApp: TextView
|
||||||
private lateinit var settings: TextView
|
private lateinit var settings: TextView
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
return inflater.inflate(R.layout.fragment_more, container, false)
|
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.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
terminateDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
terminateDialog.setPositiveButton(getString(R.string.ok)) { diag: DialogInterface?, _: Int ->
|
||||||
if (doNotShowAgain){
|
runBlocking {
|
||||||
mainSharedPreferencesEditor.putBoolean("ask_terminate_app", false)
|
val job : Job = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
mainSharedPreferencesEditor.commit()
|
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()
|
terminateDialog.show()
|
||||||
}else{
|
}else{
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,12 @@ class TerminalActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.shortcuts -> {
|
R.id.shortcuts -> {
|
||||||
if (shortcutCount > 0){
|
lifecycleScope.launch {
|
||||||
showShortcuts()
|
if (shortcutCount > 0){
|
||||||
|
UiUtil.showShortcuts(this@TerminalActivity, commandTemplateViewModel){sh ->
|
||||||
|
input!!.text.insert(input!!.selectionStart, "$sh ")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.folder -> {
|
R.id.folder -> {
|
||||||
|
|
@ -295,35 +299,6 @@ class TerminalActivity : BaseActivity() {
|
||||||
topAppBar!!.menu.forEach { it.isEnabled = false }
|
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(
|
private var commandPathResultLauncher = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) { result ->
|
) { result ->
|
||||||
|
|
|
||||||
|
|
@ -550,8 +550,6 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finalMessage.append("${getString(R.string.restart)}?")
|
|
||||||
|
|
||||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||||
builder.setTitle(getString(R.string.restore))
|
builder.setTitle(getString(R.string.restore))
|
||||||
builder.setMessage(finalMessage)
|
builder.setMessage(finalMessage)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.Converters
|
|
||||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
|
@ -134,15 +133,17 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun getVideo(url: String): List<ResultItem?> {
|
fun getYoutubeVideo(url: String): List<ResultItem?> {
|
||||||
return try {
|
return try {
|
||||||
val id = getIDFromYoutubeURL(url)
|
val id = getIDFromYoutubeURL(url)
|
||||||
val res = genericRequest("$pipedURL/streams/$id")
|
val res = genericRequest("$pipedURL/streams/$id")
|
||||||
if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON(
|
if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON(
|
||||||
res, id
|
res, url
|
||||||
))
|
))
|
||||||
}catch (e: Exception){
|
}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
|
return video
|
||||||
}
|
}
|
||||||
private fun createVideoFromPipedJSON(obj: JSONObject, id: String): ResultItem? {
|
private fun createVideoFromPipedJSON(obj: JSONObject, url: String): ResultItem? {
|
||||||
var video: ResultItem? = null
|
var video: ResultItem? = null
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
val id = getIDFromYoutubeURL(url)
|
||||||
val title = Html.fromHtml(obj.getString("title").toString()).toString()
|
val title = Html.fromHtml(obj.getString("title").toString()).toString()
|
||||||
val author = try {
|
val author = try {
|
||||||
Html.fromHtml(obj.getString("uploader").toString()).toString()
|
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 duration = formatIntegerDuration(obj.getInt("duration"), Locale.US)
|
||||||
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
|
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
|
||||||
val url = "https://www.youtube.com/watch?v=$id"
|
|
||||||
val formats : ArrayList<Format> = ArrayList()
|
val formats : ArrayList<Format> = ArrayList()
|
||||||
|
|
||||||
if(sharedPreferences.getString("formats_source", "yt-dlp") == "piped"){
|
if(sharedPreferences.getString("formats_source", "yt-dlp") == "piped"){
|
||||||
|
|
@ -452,9 +454,12 @@ class InfoUtil(private val context: Context) {
|
||||||
request.addOption("--skip-download")
|
request.addOption("--skip-download")
|
||||||
request.addOption("-R", "1")
|
request.addOption("-R", "1")
|
||||||
request.addOption("--socket-timeout", "5")
|
request.addOption("--socket-timeout", "5")
|
||||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
|
||||||
if (cookiesFile.exists()) {
|
if (sharedPreferences.getBoolean("use_cookies", false)){
|
||||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||||
|
if (cookiesFile.exists()) {
|
||||||
|
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val proxy = sharedPreferences.getString("proxy", "")
|
val proxy = sharedPreferences.getString("proxy", "")
|
||||||
|
|
@ -626,7 +631,16 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var urls = "";
|
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,
|
items.add(ResultItem(0,
|
||||||
url,
|
url,
|
||||||
|
|
@ -927,7 +941,7 @@ class InfoUtil(private val context: Context) {
|
||||||
if(downloadItem.type != DownloadViewModel.Type.command){
|
if(downloadItem.type != DownloadViewModel.Type.command){
|
||||||
if (downloadItem.SaveThumb) {
|
if (downloadItem.SaveThumb) {
|
||||||
request.addOption("--write-thumbnail")
|
request.addOption("--write-thumbnail")
|
||||||
request.addOption("--convert-thumbnails", "png")
|
request.addOption("--convert-thumbnails", "jpg")
|
||||||
}
|
}
|
||||||
if (!sharedPreferences.getBoolean("mtime", false)){
|
if (!sharedPreferences.getBoolean("mtime", false)){
|
||||||
request.addOption("--no-mtime")
|
request.addOption("--no-mtime")
|
||||||
|
|
@ -991,6 +1005,10 @@ class InfoUtil(private val context: Context) {
|
||||||
conf.absolutePath
|
conf.absolutePath
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sharedPreferences.getBoolean("write_description", false)){
|
||||||
|
request.addOption("--write-description")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
|
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
|
||||||
|
|
@ -1041,7 +1059,7 @@ class InfoUtil(private val context: Context) {
|
||||||
|
|
||||||
if (downloadItem.audioPreferences.embedThumb) {
|
if (downloadItem.audioPreferences.embedThumb) {
|
||||||
request.addOption("--embed-thumbnail")
|
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)){
|
if (sharedPreferences.getBoolean("crop_thumbnail", true)){
|
||||||
try {
|
try {
|
||||||
val config = File(context.cacheDir.absolutePath + "/downloads/${downloadItem.id}/config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt")
|
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()){
|
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||||
request.addOption("--split-chapters")
|
request.addOption("--split-chapters")
|
||||||
|
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
||||||
}else{
|
}else{
|
||||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import android.text.TextWatcher
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
|
|
@ -31,6 +32,8 @@ import androidx.core.content.FileProvider
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
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.DateValidatorPointForward
|
||||||
import com.google.android.material.datepicker.MaterialDatePicker
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
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.textfield.TextInputLayout
|
||||||
import com.google.android.material.timepicker.MaterialTimePicker
|
import com.google.android.material.timepicker.MaterialTimePicker
|
||||||
import com.google.android.material.timepicker.TimeFormat
|
import com.google.android.material.timepicker.TimeFormat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
@ -100,6 +105,7 @@ object UiUtil {
|
||||||
val ok : Button = bottomSheet.findViewById(R.id.template_create)!!
|
val ok : Button = bottomSheet.findViewById(R.id.template_create)!!
|
||||||
val title : TextInputLayout = bottomSheet.findViewById(R.id.title)!!
|
val title : TextInputLayout = bottomSheet.findViewById(R.id.title)!!
|
||||||
val content : TextInputLayout = bottomSheet.findViewById(R.id.content)!!
|
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 shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!!
|
||||||
val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!!
|
val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!!
|
||||||
|
|
||||||
|
|
@ -148,6 +154,8 @@ object UiUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraCommandsSwitch.isChecked = item!!.useAsExtraCommand
|
||||||
|
|
||||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
||||||
shortcutsChipGroup.removeAllViews()
|
shortcutsChipGroup.removeAllViews()
|
||||||
it.forEach {shortcut ->
|
it.forEach {shortcut ->
|
||||||
|
|
@ -166,7 +174,7 @@ object UiUtil {
|
||||||
|
|
||||||
ok.setOnClickListener {
|
ok.setOnClickListener {
|
||||||
if (item == null){
|
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)
|
commandTemplateViewModel.insert(t)
|
||||||
newTemplate(t)
|
newTemplate(t)
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -507,4 +515,48 @@ object UiUtil {
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
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) {
|
) : Worker(context, workerParams) {
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
itemId = inputData.getLong("id", 0)
|
itemId = inputData.getLong("id", 0)
|
||||||
if (itemId == 0L) return Result.failure()
|
if (itemId == 0L || isStopped) return Result.failure()
|
||||||
|
|
||||||
|
|
||||||
val notificationUtil = NotificationUtil(context)
|
val notificationUtil = NotificationUtil(context)
|
||||||
val infoUtil = InfoUtil(context)
|
val infoUtil = InfoUtil(context)
|
||||||
|
|
@ -74,6 +73,7 @@ class DownloadWorker(
|
||||||
Log.e(TAG, downloadItem.toString())
|
Log.e(TAG, downloadItem.toString())
|
||||||
|
|
||||||
runBlocking{
|
runBlocking{
|
||||||
|
YoutubeDL.getInstance().destroyProcessById(itemId.toString())
|
||||||
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
|
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
|
||||||
}
|
}
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
@ -118,7 +118,7 @@ class DownloadWorker(
|
||||||
}
|
}
|
||||||
runCatching {
|
runCatching {
|
||||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
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
|
val title: String = downloadItem.title
|
||||||
notificationUtil.updateDownloadNotification(
|
notificationUtil.updateDownloadNotification(
|
||||||
downloadItem.id.toInt(),
|
downloadItem.id.toInt(),
|
||||||
|
|
@ -137,16 +137,16 @@ class DownloadWorker(
|
||||||
runBlocking {
|
runBlocking {
|
||||||
var finalPaths : List<String>?
|
var finalPaths : List<String>?
|
||||||
//move file from internal to set download directory
|
//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 {
|
try {
|
||||||
finalPaths = withContext(Dispatchers.IO){
|
finalPaths = withContext(Dispatchers.IO){
|
||||||
FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
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()){
|
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{
|
}else{
|
||||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +177,7 @@ class DownloadWorker(
|
||||||
|
|
||||||
if (wasQuickDownloaded){
|
if (wasQuickDownloaded){
|
||||||
runCatching {
|
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 {
|
runBlocking {
|
||||||
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
|
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
|
|
@ -242,7 +242,8 @@ class DownloadWorker(
|
||||||
var wasQuickDownloaded = false
|
var wasQuickDownloaded = false
|
||||||
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
|
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
|
||||||
runCatching {
|
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)
|
val info = infoUtil.getMissingInfo(downloadItem.url)
|
||||||
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
|
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
|
||||||
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
|
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
|
||||||
|
|
@ -259,10 +260,14 @@ class DownloadWorker(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopped() {
|
override fun onStopped() {
|
||||||
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
|
destroyYTDLProcess()
|
||||||
super.onStopped()
|
super.onStopped()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun destroyYTDLProcess(){
|
||||||
|
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var itemId: Long = 0
|
var itemId: Long = 0
|
||||||
const val TAG = "DownloadWorker"
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:pivotX="65%"
|
android:shape="rectangle">
|
||||||
android:pivotY="20%"
|
|
||||||
android:toDegrees="250"
|
|
||||||
android:fromDegrees="270">
|
|
||||||
|
|
||||||
<shape android:shape="rectangle">
|
<corners
|
||||||
<solid android:color="?android:colorAccent"/>
|
android:radius="50dp" />
|
||||||
<size
|
|
||||||
android:width="40dp"
|
|
||||||
android:height="20dp"/>
|
|
||||||
<corners
|
|
||||||
android:topLeftRadius="20dp"
|
|
||||||
android:topRightRadius="20dp"/>
|
|
||||||
</shape>
|
|
||||||
|
|
||||||
</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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/command_template_item_constraint"
|
android:id="@+id/command_template_item_constraint"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
@ -31,24 +32,26 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||||
|
|
||||||
<!-- <View-->
|
<TextView
|
||||||
<!-- android:id="@+id/divider"-->
|
android:id="@+id/useInExtraCommands"
|
||||||
<!-- style="@style/Divider.Vertical"-->
|
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||||
<!-- android:layout_height="0dp"-->
|
android:layout_width="wrap_content"
|
||||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
android:layout_height="wrap_content"
|
||||||
<!-- app:layout_constraintEnd_toStartOf="@+id/check"-->
|
android:background="@drawable/rounded_corner"
|
||||||
<!-- app:layout_constraintStart_toEndOf="@+id/title"-->
|
android:backgroundTint="?attr/colorSecondary"
|
||||||
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
android:clickable="false"
|
||||||
|
android:visibility="gone"
|
||||||
<!-- <RadioButton-->
|
android:ellipsize="end"
|
||||||
<!-- android:id="@+id/check"-->
|
android:text="@string/extra_command"
|
||||||
<!-- android:layout_width="wrap_content"-->
|
android:gravity="center"
|
||||||
<!-- android:layout_height="wrap_content"-->
|
android:maxLength="17"
|
||||||
<!-- android:gravity="center"-->
|
android:maxLines="1"
|
||||||
<!-- android:minWidth="0dp"-->
|
android:minWidth="30dp"
|
||||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
android:paddingHorizontal="5dp"
|
||||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
android:textSize="12sp"
|
||||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
android:textStyle="bold"
|
||||||
<!-- app:layout_constraintVertical_bias="0.558" />-->
|
app:cornerRadius="10dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/content" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,18 @@
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</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
|
<View
|
||||||
style="@style/Divider.Horizontal"
|
style="@style/Divider.Horizontal"
|
||||||
android:layout_marginVertical="10dp" />
|
android:layout_marginVertical="10dp" />
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/from_textinput"
|
android:id="@+id/from_textinput"
|
||||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||||
android:layout_width="80dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/start">
|
android:hint="@string/start">
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/to_textinput"
|
android:id="@+id/to_textinput"
|
||||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||||
android:layout_width="80dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/end"
|
android:hint="@string/end"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
|
||||||
|
|
@ -1,90 +1,147 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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_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_height="wrap_content"
|
||||||
android:layout_margin="20dp"
|
android:orientation="vertical"
|
||||||
android:orientation="vertical">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TextView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
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"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_marginVertical="10dp"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
android:layout_marginHorizontal="20dp"
|
||||||
android:layout_height="wrap_content">
|
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
|
<LinearLayout
|
||||||
|
android:id="@+id/linear"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:padding="10dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/currentTitle"
|
android:id="@+id/current"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/current"
|
android:layout_marginHorizontal="20dp"
|
||||||
android:textSize="12sp"
|
android:layout_marginVertical="5dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintTop_toBottomOf="@+id/title">
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/currentText"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="vertical"
|
||||||
android:fontFamily="monospace"
|
android:padding="10dp">
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
<TextView
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
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>
|
</LinearLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</ScrollView>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/textInputLayout"
|
android:id="@+id/textInputLayout"
|
||||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_marginVertical="10dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/current">
|
app:layout_constraintTop_toBottomOf="@+id/current">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/command"
|
android:id="@+id/command"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textMultiLine"
|
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
android:maxLines="2000" />
|
android:maxLines="2000" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/okButton"
|
</LinearLayout>
|
||||||
android:layout_marginVertical="10dp"
|
|
||||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
<Button
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/shortcuts"
|
||||||
android:layout_height="wrap_content"
|
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||||
android:text="@string/ok"
|
android:layout_width="wrap_content"
|
||||||
app:icon="@drawable/ic_check"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
|
app:icon="@drawable/ic_shortcut"
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
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"?>
|
<?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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/pause_resume"
|
android:id="@+id/pause_resume"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="30dp"
|
android:paddingHorizontal="30dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
android:paddingVertical="10dp"
|
android:paddingVertical="10dp"
|
||||||
android:text="@string/resume"
|
android:text="@string/resume"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"/>
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/download_recyclerview"
|
android:id="@+id/download_recyclerview"
|
||||||
|
|
@ -27,6 +25,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:scrollbars="none"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:fastScrollEnabled="true"
|
app:fastScrollEnabled="true"
|
||||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
|
@ -38,4 +37,4 @@
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
@ -31,13 +31,25 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
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
|
<com.google.android.material.chip.Chip
|
||||||
android:id="@+id/newCookie"
|
android:id="@+id/newCookie"
|
||||||
android:layout_margin="10dp"
|
|
||||||
style="@style/Widget.Material3.Chip.Assist"
|
style="@style/Widget.Material3.Chip.Assist"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="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"
|
android:text="@string/new_cookie"
|
||||||
app:chipIcon="@drawable/ic_plus" />
|
app:chipIcon="@drawable/ic_plus" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="200dp"
|
android:scrollbars="none"
|
||||||
app:fastScrollEnabled="true"
|
app:fastScrollEnabled="true"
|
||||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
android:id="@+id/recyclerviewhistorys"
|
android:id="@+id/recyclerviewhistorys"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="none"
|
||||||
app:fastScrollEnabled="true"
|
app:fastScrollEnabled="true"
|
||||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
|
|
||||||
|
|
@ -120,33 +120,6 @@
|
||||||
|
|
||||||
</com.google.android.material.search.SearchView>
|
</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
|
<RelativeLayout
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
@ -200,6 +173,30 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</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
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:id="@+id/home_fabs"
|
android:id="@+id/home_fabs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:fastScrollEnabled="true"
|
app:fastScrollEnabled="true"
|
||||||
|
android:scrollbars="none"
|
||||||
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
|
@ -36,4 +38,4 @@
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
@ -80,7 +80,6 @@
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:singleLine="false"
|
android:singleLine="false"
|
||||||
|
|
@ -113,8 +112,7 @@
|
||||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:layout_marginVertical="10dp"
|
android:layout_marginHorizontal="10dp"
|
||||||
android:layout_marginEnd="5dp"
|
|
||||||
app:icon="@drawable/ic_music"
|
app:icon="@drawable/ic_music"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
@ -124,7 +122,7 @@
|
||||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:layout_margin="10dp"
|
android:layout_marginHorizontal="10dp"
|
||||||
app:icon="@drawable/ic_video"
|
app:icon="@drawable/ic_video"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
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="custom_audio_quality">استخدام جودة صوت مخصصة</string>
|
||||||
<string name="piped_instance">مثيل Piped</string>
|
<string name="piped_instance">مثيل Piped</string>
|
||||||
<string name="piped_instance_summary">إدخال خادم PIPED API، يمكن للتطبيق استخدامه لاستعلامات وتنسيقات يوتيوب</string>
|
<string name="piped_instance_summary">إدخال خادم PIPED API، يمكن للتطبيق استخدامه لاستعلامات وتنسيقات يوتيوب</string>
|
||||||
<string name="subtitle_format">صيغة الترجمة
|
<string name="subtitle_format">صيغة الترجمة</string>
|
||||||
\n</string>
|
|
||||||
<string name="hide_thumbnails">إخفاء الصور المصغرة من الشاشة المحددة</string>
|
<string name="hide_thumbnails">إخفاء الصور المصغرة من الشاشة المحددة</string>
|
||||||
<string name="hide_terminal">إخفاء أيقونة سطر الأوامر من قائمة \"مشاركة\"</string>
|
|
||||||
<string name="saved">المحفوظة</string>
|
<string name="saved">المحفوظة</string>
|
||||||
<string name="clear_saved">تنظيف المحفوظة</string>
|
<string name="clear_saved">تنظيف المحفوظة</string>
|
||||||
<string name="save_for_later">حفظ، للتحميل فيما بعد؟</string>
|
<string name="save_for_later">حفظ، للتحميل فيما بعد؟</string>
|
||||||
|
|
|
||||||
|
|
@ -275,10 +275,8 @@
|
||||||
<string name="retries">Wiederholungen</string>
|
<string name="retries">Wiederholungen</string>
|
||||||
<string name="fragment_retries">Fragmentwiederholungen</string>
|
<string name="fragment_retries">Fragmentwiederholungen</string>
|
||||||
<string name="format_order">Formatreihenfolge</string>
|
<string name="format_order">Formatreihenfolge</string>
|
||||||
<string name="subtitle_format">Untertitelformat
|
<string name="subtitle_format">Untertitelformat</string>
|
||||||
\n</string>
|
|
||||||
<string name="hide_thumbnails">Vorschaubilder verstecken</string>
|
<string name="hide_thumbnails">Vorschaubilder verstecken</string>
|
||||||
<string name="hide_terminal">Terminal im Freigabemenü ausblenden</string>
|
|
||||||
<string name="saved">Gespeichert</string>
|
<string name="saved">Gespeichert</string>
|
||||||
<string name="save_for_later">Download für später merken\?</string>
|
<string name="save_for_later">Download für später merken\?</string>
|
||||||
<string name="clear_saved">Gespeichertes leeren</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="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="current">Bieżące polecenie</string>
|
||||||
<string name="hide_thumbnails">Ukryj miniatury</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="saved">Zapisane</string>
|
||||||
<string name="clear_saved">Wyczyść zapisane</string>
|
<string name="clear_saved">Wyczyść zapisane</string>
|
||||||
<string name="save_for_later">Zachować pobieranie na później\?</string>
|
<string name="save_for_later">Zachować pobieranie na później\?</string>
|
||||||
<string name="subtitle_format">Format napisów
|
<string name="subtitle_format">Format napisów</string>
|
||||||
\n</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -279,7 +279,6 @@
|
||||||
<string name="force_keyframes_summary">Processo mais lento, mas cortes mais precisos</string>
|
<string name="force_keyframes_summary">Processo mais lento, mas cortes mais precisos</string>
|
||||||
<string name="subtitle_format">Formato da legenda</string>
|
<string name="subtitle_format">Formato da legenda</string>
|
||||||
<string name="hide_thumbnails">Ocultar miniaturas</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="saved">Salvou</string>
|
||||||
<string name="clear_saved">Remoção Concluída</string>
|
<string name="clear_saved">Remoção Concluída</string>
|
||||||
<string name="save_for_later">Salvar download para mais tarde\?</string>
|
<string name="save_for_later">Salvar download para mais tarde\?</string>
|
||||||
|
|
|
||||||
|
|
@ -281,10 +281,8 @@
|
||||||
<string name="saved">Guardado</string>
|
<string name="saved">Guardado</string>
|
||||||
<string name="clear_saved">Limpar 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="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
|
<string name="subtitle_format">Formato da legenda</string>
|
||||||
\n</string>
|
|
||||||
<string name="hide_thumbnails">Esconder miniaturas</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="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="save_for_later">Guardar a transferência para mais tarde\?</string>
|
||||||
<string name="force_keyframes">Forçar quadros-chave nos cortes</string>
|
<string name="force_keyframes">Forçar quadros-chave nos cortes</string>
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,6 @@
|
||||||
<string name="current">Текущая команда</string>
|
<string name="current">Текущая команда</string>
|
||||||
<string name="subtitle_format">Формат субтитров</string>
|
<string name="subtitle_format">Формат субтитров</string>
|
||||||
<string name="hide_thumbnails">Скрыть миниатюры</string>
|
<string name="hide_thumbnails">Скрыть миниатюры</string>
|
||||||
<string name="hide_terminal">Скрыть терминал из меню «Поделиться»</string>
|
|
||||||
<string name="saved">Сохранено</string>
|
<string name="saved">Сохранено</string>
|
||||||
<string name="clear_saved">Очистить сохраненное</string>
|
<string name="clear_saved">Очистить сохраненное</string>
|
||||||
<string name="save_for_later">Сохранить загрузку на потом\?</string>
|
<string name="save_for_later">Сохранить загрузку на потом\?</string>
|
||||||
|
|
|
||||||
|
|
@ -98,10 +98,8 @@
|
||||||
<string name="save_for_later">บันทึกการดาวน์โหลดสำหรับภายหลัง\?</string>
|
<string name="save_for_later">บันทึกการดาวน์โหลดสำหรับภายหลัง\?</string>
|
||||||
<string name="clear_saved">ล้างข้อมูลที่บันทึกไว้</string>
|
<string name="clear_saved">ล้างข้อมูลที่บันทึกไว้</string>
|
||||||
<string name="saved">บันทึกแล้ว</string>
|
<string name="saved">บันทึกแล้ว</string>
|
||||||
<string name="hide_terminal">ซ่อน Terminal จากเมนูแชร์</string>
|
|
||||||
<string name="hide_thumbnails">ซ่อนภาพขนาดย่อ</string>
|
<string name="hide_thumbnails">ซ่อนภาพขนาดย่อ</string>
|
||||||
<string name="subtitle_format">รูปแบบคำบรรยาย
|
<string name="subtitle_format">รูปแบบคำบรรยาย</string>
|
||||||
\n</string>
|
|
||||||
<string name="current">คำสั่งปัจจุบัน</string>
|
<string name="current">คำสั่งปัจจุบัน</string>
|
||||||
<string name="use_extra_commands">เพิ่มคำสั่งพิเศษ</string>
|
<string name="use_extra_commands">เพิ่มคำสั่งพิเศษ</string>
|
||||||
<string name="force_keyframes_summary">กระบวนการช้าลง แต่มีการตัดที่แม่นยำยิ่งขึ้น</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="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="current">Geçerli Komut</string>
|
||||||
<string name="save_for_later">Daha Sonra İndirmek için Kaydedilsin mi\?</string>
|
<string name="save_for_later">Daha Sonra İndirmek için Kaydedilsin mi\?</string>
|
||||||
<string name="subtitle_format">Altyazı Biçimi
|
<string name="subtitle_format">Altyazı Biçimi</string>
|
||||||
\n</string>
|
|
||||||
<string name="saved">Kaydedildi</string>
|
<string name="saved">Kaydedildi</string>
|
||||||
<string name="clear_saved">Kaydedilenleri Temizle</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>
|
<string name="hide_thumbnails">Küçük Resimleri Gizle</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -281,11 +281,9 @@
|
||||||
<string name="current">Поточна команда</string>
|
<string name="current">Поточна команда</string>
|
||||||
<string name="use_extra_commands_summary">Додайте свої додаткові команди перед завантаженням аудіо/відео</string>
|
<string name="use_extra_commands_summary">Додайте свої додаткові команди перед завантаженням аудіо/відео</string>
|
||||||
<string name="hide_thumbnails">Приховати мініатюри</string>
|
<string name="hide_thumbnails">Приховати мініатюри</string>
|
||||||
<string name="hide_terminal">Приховати термінал у меню спільного доступу</string>
|
|
||||||
<string name="saved">Збережено</string>
|
<string name="saved">Збережено</string>
|
||||||
<string name="clear_saved">Очистити збережене</string>
|
<string name="clear_saved">Очистити збережене</string>
|
||||||
<string name="subtitle_format">Формат субтитрів
|
<string name="subtitle_format">Формат субтитрів</string>
|
||||||
\n</string>
|
|
||||||
<string name="save_for_later">Зберегти завантаження на потім\?</string>
|
<string name="save_for_later">Зберегти завантаження на потім\?</string>
|
||||||
<string name="orange">Помаранчевий</string>
|
<string name="orange">Помаранчевий</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -278,10 +278,8 @@
|
||||||
<string name="use_extra_commands">新增額外指令</string>
|
<string name="use_extra_commands">新增額外指令</string>
|
||||||
<string name="use_extra_commands_summary">為了音訊 / 影片下載,請在圖形使用者介面配置中新增額外的指令</string>
|
<string name="use_extra_commands_summary">為了音訊 / 影片下載,請在圖形使用者介面配置中新增額外的指令</string>
|
||||||
<string name="hide_thumbnails">隱藏縮略圖</string>
|
<string name="hide_thumbnails">隱藏縮略圖</string>
|
||||||
<string name="subtitle_format">字幕格式
|
<string name="subtitle_format">字幕格式</string>
|
||||||
\n</string>
|
|
||||||
<string name="force_keyframes_summary">較為緩慢的處理過程,但能得到更準確的剪輯結果</string>
|
<string name="force_keyframes_summary">較為緩慢的處理過程,但能得到更準確的剪輯結果</string>
|
||||||
<string name="hide_terminal">隱藏分享選單中的終端機</string>
|
|
||||||
<string name="saved">已儲存</string>
|
<string name="saved">已儲存</string>
|
||||||
<string name="clear_saved">清除已儲存的內容</string>
|
<string name="clear_saved">清除已儲存的內容</string>
|
||||||
<string name="save_for_later">儲存下載以供日後使用?</string>
|
<string name="save_for_later">儲存下載以供日後使用?</string>
|
||||||
|
|
|
||||||
|
|
@ -294,4 +294,8 @@
|
||||||
<string name="saved">Saved</string>
|
<string name="saved">Saved</string>
|
||||||
<string name="clear_saved">Clear Saved</string>
|
<string name="clear_saved">Clear Saved</string>
|
||||||
<string name="save_for_later">Save Download for Later?</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>
|
</resources>
|
||||||
|
|
@ -53,6 +53,14 @@
|
||||||
app:useSimpleSummaryProvider="true"
|
app:useSimpleSummaryProvider="true"
|
||||||
app:title="@string/subtitle_format" />
|
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
|
<SwitchPreferenceCompat
|
||||||
android:widgetLayout="@layout/preferece_material_switch"
|
android:widgetLayout="@layout/preferece_material_switch"
|
||||||
app:defaultValue="true"
|
app:defaultValue="true"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ buildscript {
|
||||||
coroutineVer = "1.6.4"
|
coroutineVer = "1.6.4"
|
||||||
retrofitVer = "2.9.0"
|
retrofitVer = "2.9.0"
|
||||||
kodeinVer = "7.16.0"
|
kodeinVer = "7.16.0"
|
||||||
navVer = "2.5.3"
|
navVer = "2.6.0"
|
||||||
media3_version = "1.1.0"
|
media3_version = "1.1.0"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue