1.7.2 pre
- Increased the height of the history card a slight bit - Fixed app not using the -S format sorter in normal GUI downloads - Added the multiple download card as an option to disable the swipe gestures - Added a recyclerview to the search results because they were buggy before and would not show sometimes - Added a new history item card design in cases if you quick-downloaded a playlist or if you made multiple cuts of a file. Instead of being separate, they are bundled and you can share them all at once and if you want to open the file a new dialog will show telling you to choose which one. If any of them is deleted, they are greyed out - Fixed the shortcuts behaviour by allowing duplicate shortcuts to be added to textbox and to not check - Added format filtering in the format list bottom sheet. You can filter between ALL, SUGGESTED, SMALLEST, GENERIC. Suggested formats are built upon your app preferences like your preferred codec, container, quality. Smallest formats are all formats for each resolution with the smallest filesize. Generic are formats you see if an item has not updated the formats yet, in case you want to use those for some reason - Added clipboard button right in the home screen for quick access to the url you copied instead of going to the searchview. That item is also available there aswell - Added ability to show the URL in a history item if the download produced no title for it - Added zoom-in zoom-out slider for logs and terminal screens. - Added more options of datafetching for titles and authors, like track, alt_title to avoid the default youtube naming scheme when available. Useful for audio downloads - Since some people are confused. In the download card each tab item is independent and they each create a distinct download item and when you press download the app picks from the tab you are currently. If you want to select the audio format in the video tab you can just open the format list and scroll to the bottom for the audio formats. You can select multiple if you want and then press ok. But since some people thought that selecting the audio in audio tab would apply to the video tab, i added the ability to synchronise that format automatically in case people dont know about this lol - Other small bug fixes
This commit is contained in:
parent
e294ca86d5
commit
dd3578bc48
99 changed files with 2854 additions and 1436 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -6,4 +6,5 @@
|
|||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
/benchmark
|
||||
/benchmark
|
||||
*.png
|
||||
|
|
@ -10,7 +10,7 @@ plugins {
|
|||
def properties = new Properties()
|
||||
def versionMajor = 1
|
||||
def versionMinor = 7
|
||||
def versionPatch = 1
|
||||
def versionPatch = 2
|
||||
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
|
||||
def versionExt = ""
|
||||
|
||||
|
|
|
|||
598
app/schemas/com.deniscerri.ytdlnis.database.DBManager/14.json
Normal file
598
app/schemas/com.deniscerri.ytdlnis.database.DBManager/14.json
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 14,
|
||||
"identityHash": "5cea521e1a26473b2ec5298791f10ac4",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
"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, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `creationTime` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formats",
|
||||
"columnName": "formats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "urls",
|
||||
"columnName": "urls",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chapters",
|
||||
"columnName": "chapters",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistURL",
|
||||
"columnName": "playlistURL",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistIndex",
|
||||
"columnName": "playlistIndex",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "creationTime",
|
||||
"columnName": "creationTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"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, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadId",
|
||||
"columnName": "downloadId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"fieldPath": "command",
|
||||
"columnName": "command",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"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, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "container",
|
||||
"columnName": "container",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'Default'"
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSections",
|
||||
"columnName": "downloadSections",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "allFormats",
|
||||
"columnName": "allFormats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSize",
|
||||
"columnName": "downloadSize",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "audioPreferences",
|
||||
"columnName": "audioPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "videoPreferences",
|
||||
"columnName": "videoPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "extraCommands",
|
||||
"columnName": "extraCommands",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "customFileNameTemplate",
|
||||
"columnName": "customFileNameTemplate",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "SaveThumb",
|
||||
"columnName": "SaveThumb",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'Queued'"
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadStartTime",
|
||||
"columnName": "downloadStartTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"fieldPath": "logID",
|
||||
"columnName": "logID",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistURL",
|
||||
"columnName": "playlistURL",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistIndex",
|
||||
"columnName": "playlistIndex",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"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, `useAsExtraCommand` INTEGER NOT NULL DEFAULT 0, `useAsExtraCommandAudio` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandVideo` INTEGER NOT NULL DEFAULT 1)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommand",
|
||||
"columnName": "useAsExtraCommand",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommandAudio",
|
||||
"columnName": "useAsExtraCommandAudio",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "1"
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommandVideo",
|
||||
"columnName": "useAsExtraCommandVideo",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "1"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "searchHistory",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "templateShortcuts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "cookies",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "logs",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadType` TEXT NOT NULL, `downloadTime` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadType",
|
||||
"columnName": "downloadType",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadTime",
|
||||
"columnName": "downloadTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "terminalDownloads",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `command` TEXT NOT NULL, `log` TEXT DEFAULT '')",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "command",
|
||||
"columnName": "command",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "log",
|
||||
"columnName": "log",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false,
|
||||
"defaultValue": "''"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5cea521e1a26473b2ec5298791f10ac4')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,12 @@ class Converters {
|
|||
@TypeConverter
|
||||
fun listOfFormatsToString(list: List<Format?>?) = Gson().toJson(list).toString()
|
||||
|
||||
@TypeConverter
|
||||
fun stringToListOfStrings(value: String) = Gson().fromJson(value, Array<String>::class.java).toList()
|
||||
|
||||
@TypeConverter
|
||||
fun listOfStringsToString(list: List<String>) = Gson().toJson(list).toString()
|
||||
|
||||
@TypeConverter
|
||||
fun formatToString(format: Format): String = Gson().toJson(format)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
LogItem::class,
|
||||
TerminalItem::class
|
||||
],
|
||||
version = 13,
|
||||
version = 14,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
|
|
@ -36,7 +36,8 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
AutoMigration (from = 9, to = 10),
|
||||
AutoMigration (from = 10, to = 11),
|
||||
AutoMigration (from = 11, to = 12),
|
||||
AutoMigration (from = 12, to = 13)
|
||||
AutoMigration (from = 12, to = 13),
|
||||
//AutoMigration (from = 13, to = 14), MANUALLY HANDLED
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
@ -66,6 +67,7 @@ abstract class DBManager : RoomDatabase(){
|
|||
DBManager::class.java,
|
||||
"YTDLnisDatabase"
|
||||
)
|
||||
.addMigrations(*Migrations.migrationList)
|
||||
.build()
|
||||
instance = dbInstance
|
||||
dbInstance
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package com.deniscerri.ytdlnis.database
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.Outline
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.OvalShape
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.MediaMetadataRetriever.METADATA_KEY_DURATION
|
||||
import android.net.Uri
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.withStarted
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.work.impl.Migration_12_13
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.neo.highlight.core.Highlight
|
||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import kotlinx.coroutines.launch
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
object Migrations {
|
||||
|
||||
@SuppressLint("Range")
|
||||
val migrationList = arrayOf(
|
||||
//Moving from one file path to multiple file paths of a history item
|
||||
Migration(13, 14){database ->
|
||||
val cursor = database.query("SELECT * FROM history")
|
||||
while(cursor.moveToNext()) {
|
||||
val id = cursor.getLong(cursor.getColumnIndex("id"))
|
||||
val path = cursor.getString(cursor.getColumnIndex("downloadPath"))
|
||||
val newPath = "[\"${path.replace("\"", "\\\"").replace("'", "''")}\"]"
|
||||
database.execSQL("UPDATE history SET downloadPath = '${newPath}' WHERE id = $id")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -138,6 +138,9 @@ interface DownloadDao {
|
|||
@Upsert
|
||||
suspend fun update(item: DownloadItem)
|
||||
|
||||
@Update
|
||||
suspend fun updateWithoutUpsert(item: DownloadItem)
|
||||
|
||||
@Query("UPDATE downloads SET logID=null")
|
||||
fun removeAllLogID()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ data class HistoryItem(
|
|||
val thumb: String,
|
||||
val type: DownloadViewModel.Type,
|
||||
val time: Long,
|
||||
val downloadPath: String,
|
||||
val downloadPath: List<String>,
|
||||
val website: String,
|
||||
val format: Format,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
||||
data class SearchSuggestionItem(
|
||||
var text: String,
|
||||
val type: SearchSuggestionType,
|
||||
)
|
||||
|
||||
enum class SearchSuggestionType{
|
||||
SUGGESTION, HISTORY, CLIPBOARD
|
||||
}
|
||||
|
|
@ -66,6 +66,10 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
downloadDao.update(item)
|
||||
}
|
||||
|
||||
suspend fun updateWithoutUpsert(item: DownloadItem){
|
||||
kotlin.runCatching { downloadDao.updateWithoutUpsert(item) }
|
||||
}
|
||||
|
||||
|
||||
suspend fun setDownloadStatus(item: DownloadItem, status: Status){
|
||||
item.status = status.toString()
|
||||
|
|
|
|||
|
|
@ -48,14 +48,18 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
suspend fun delete(item: HistoryItem, deleteFile: Boolean){
|
||||
historyDao.delete(item.id)
|
||||
if (deleteFile){
|
||||
FileUtil.deleteFile(item.downloadPath)
|
||||
item.downloadPath.forEach {
|
||||
FileUtil.deleteFile(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteAll(deleteFile: Boolean = false){
|
||||
if (deleteFile){
|
||||
historyDao.getAllHistoryList().forEach { item ->
|
||||
FileUtil.deleteFile(item.downloadPath)
|
||||
item.downloadPath.forEach {
|
||||
FileUtil.deleteFile(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
historyDao.deleteAll()
|
||||
|
|
@ -72,7 +76,7 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
suspend fun clearDeletedHistory(){
|
||||
items.collectLatest {
|
||||
it.forEach { item ->
|
||||
if (!FileUtil.exists(item.downloadPath)){
|
||||
if (item.downloadPath.all { path -> !FileUtil.exists(path) }){
|
||||
historyDao.delete(item.id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
|
|
@ -424,8 +425,15 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
|
||||
val audioPreferences = AudioPreferences(embedThumb, cropThumb,false, ArrayList(sponsorblock!!))
|
||||
val videoPreferences = VideoPreferences(embedSubs, addChapters, false, ArrayList(sponsorblock), saveSubs)
|
||||
val downloadPath = File(historyItem.downloadPath)
|
||||
val path = if (downloadPath.exists()) downloadPath.parent else defaultPath
|
||||
var path = defaultPath
|
||||
historyItem.downloadPath.first().apply {
|
||||
File(this).parent?.apply {
|
||||
if (File(this).exists()){
|
||||
path = this
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return DownloadItem(0,
|
||||
historyItem.url,
|
||||
historyItem.title,
|
||||
|
|
@ -443,23 +451,37 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
}
|
||||
|
||||
|
||||
fun getPreferredAudioRequirements(): MutableList<(Format) -> Boolean> {
|
||||
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
|
||||
requirements.add {it: Format -> audioFormatIDPreference.contains(it.format_id)}
|
||||
|
||||
sharedPreferences.getString("audio_language", "")?.apply {
|
||||
if (this.isNotBlank()){
|
||||
requirements.add { it: Format -> it.lang == this }
|
||||
}
|
||||
}
|
||||
|
||||
requirements.add {it: Format -> it.container == audioContainer }
|
||||
requirements.add {it: Format -> "^(${audioCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.acodec)}
|
||||
return requirements
|
||||
}
|
||||
|
||||
fun getPreferredVideoRequirements(): MutableList<(Format) -> Boolean> {
|
||||
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
|
||||
requirements.add { it: Format -> formatIDPreference.contains(it.format_id) }
|
||||
requirements.add { it: Format -> if (videoContainer == "mp4") it.container.equals("mpeg_4", true) else it.container.equals(videoContainer, true)}
|
||||
requirements.add { it: Format -> it.format_note.contains(videoQualityPreference.split("_")[0].dropLast(1)) }
|
||||
requirements.add { it: Format -> "^(${videoCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.vcodec)}
|
||||
return requirements
|
||||
}
|
||||
|
||||
fun getFormat(formats: List<Format>, type: Type) : Format {
|
||||
when(type) {
|
||||
Type.audio -> {
|
||||
return cloneFormat (
|
||||
try {
|
||||
val theFormats = formats.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
|
||||
requirements.add {it: Format -> audioFormatIDPreference.contains(it.format_id)}
|
||||
|
||||
sharedPreferences.getString("audio_language", "")?.apply {
|
||||
if (this.isNotBlank()){
|
||||
requirements.add { it: Format -> it.lang == this }
|
||||
}
|
||||
}
|
||||
|
||||
requirements.add {it: Format -> it.container == audioContainer }
|
||||
requirements.add {it: Format -> "^(${audioCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.acodec)}
|
||||
val requirements = getPreferredAudioRequirements()
|
||||
theFormats.maxByOrNull { f -> requirements.count{req -> req(f)} } ?: throw Exception()
|
||||
}catch (e: Exception){
|
||||
bestAudioFormat
|
||||
|
|
@ -476,11 +498,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
theFormats.last()
|
||||
}
|
||||
else /*best*/ -> {
|
||||
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
|
||||
requirements.add { it: Format -> formatIDPreference.contains(it.format_id) }
|
||||
requirements.add { it: Format -> if (videoContainer == "mp4") it.container.equals("mpeg_4", true) else it.container.equals(videoContainer, true)}
|
||||
requirements.add { it: Format -> it.format_note.contains(videoQualityPreference.split("_")[0].dropLast(1)) }
|
||||
requirements.add { it: Format -> "^(${videoCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.vcodec)}
|
||||
val requirements = getPreferredVideoRequirements()
|
||||
theFormats.maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception()
|
||||
}
|
||||
}
|
||||
|
|
@ -677,7 +695,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
}else{
|
||||
//check if downloaded and file exists
|
||||
val history = withContext(Dispatchers.IO){
|
||||
historyRepository.getAllByURL(it.url).filter { item -> FileUtil.exists(item.downloadPath) }
|
||||
historyRepository.getAllByURL(it.url).filter { item -> item.downloadPath.any { path -> FileUtil.exists(path) } }
|
||||
}
|
||||
|
||||
val existingHistory = history.firstOrNull {
|
||||
|
|
@ -733,6 +751,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private suspend fun startDownloadWorker(queuedItems: List<DownloadItem>) {
|
||||
val context = App.instance
|
||||
val allowMeteredNetworks = sharedPreferences.getBoolean("metered_networks", true)
|
||||
|
|
@ -812,7 +831,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
|
||||
runBlocking {
|
||||
wasQuickDownloaded = resultDao.getCountInt() == 0
|
||||
dao.update(downloadItem)
|
||||
repository.updateWithoutUpsert(downloadItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
|||
|
||||
}
|
||||
}
|
||||
if (!isForegrounded()){
|
||||
if (!isForegrounded() && inputQueries.size > 1){
|
||||
notificationUtil.showQueriesFinished()
|
||||
}
|
||||
uiState.update {it.copy(processing = false)}
|
||||
|
|
|
|||
|
|
@ -28,18 +28,21 @@ import androidx.core.widget.doAfterTextChanged
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.models.SearchSuggestionItem
|
||||
import com.deniscerri.ytdlnis.database.models.SearchSuggestionType
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.ui.adapter.HomeAdapter
|
||||
import com.deniscerri.ytdlnis.ui.adapter.SearchSuggestionsAdapter
|
||||
import com.deniscerri.ytdlnis.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
|
|
@ -53,6 +56,7 @@ import com.google.android.material.chip.ChipGroup
|
|||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.search.SearchBar
|
||||
import com.google.android.material.search.SearchView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -64,17 +68,15 @@ import kotlinx.coroutines.withContext
|
|||
import java.util.*
|
||||
|
||||
|
||||
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListener {
|
||||
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggestionsAdapter.OnItemClickListener, OnClickListener {
|
||||
private var inputQueries: MutableList<String>? = null
|
||||
private var homeAdapter: HomeAdapter? = null
|
||||
private var searchSuggestionsAdapter: SearchSuggestionsAdapter? = null
|
||||
private var queriesConstraint: ConstraintLayout? = null
|
||||
|
||||
private var searchSuggestions: ScrollView? = null
|
||||
private var searchSuggestionsLinearLayout: LinearLayout? = null
|
||||
private var searchHistory: ScrollView? = null
|
||||
private var searchHistoryLinearLayout: LinearLayout? = null
|
||||
|
||||
private var downloadFabs: CoordinatorLayout? = null
|
||||
private var downloadAllFabCoordinator: CoordinatorLayout? = null
|
||||
private var downloadSelectedFab: ExtendedFloatingActionButton? = null
|
||||
private var downloadAllFab: ExtendedFloatingActionButton? = null
|
||||
private var clipboardFab: FloatingActionButton? = null
|
||||
private var homeFabs: CoordinatorLayout? = null
|
||||
private var infoUtil: InfoUtil? = null
|
||||
private var downloadQueue: ArrayList<ResultItem>? = null
|
||||
|
|
@ -92,9 +94,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
private var searchView: SearchView? = null
|
||||
private var providersChipGroup: ChipGroup? = null
|
||||
private var chipGroupDivider: View? = null
|
||||
private var linkYouCopied: ConstraintLayout? = null
|
||||
private var queriesChipGroup: ChipGroup? = null
|
||||
private var recyclerView: RecyclerView? = null
|
||||
private var searchSuggestionsRecyclerView: RecyclerView? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var resultsList: List<ResultItem?>? = null
|
||||
private var selectedObjects: ArrayList<ResultItem>? = null
|
||||
|
|
@ -136,17 +138,14 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
shimmerCards = view.findViewById(R.id.shimmer_results_framelayout)
|
||||
searchBar = view.findViewById(R.id.search_bar)
|
||||
searchView = view.findViewById(R.id.search_view)
|
||||
linkYouCopied = searchView?.findViewById(R.id.link_you_copied)
|
||||
appBarLayout = view.findViewById(R.id.home_appbarlayout)
|
||||
materialToolbar = view.findViewById(R.id.home_toolbar)
|
||||
queriesChipGroup = view.findViewById(R.id.queries)
|
||||
searchSuggestions = view.findViewById(R.id.search_suggestions_scroll_view)
|
||||
searchSuggestionsLinearLayout = view.findViewById(R.id.search_suggestions_linear_layout)
|
||||
searchHistory = view.findViewById(R.id.search_history_scroll_view)
|
||||
searchHistoryLinearLayout = view.findViewById(R.id.search_history_linear_layout)
|
||||
queriesConstraint = view.findViewById(R.id.queries_constraint)
|
||||
homeFabs = view.findViewById(R.id.home_fabs)
|
||||
downloadFabs = homeFabs!!.findViewById(R.id.download_selected_coordinator)
|
||||
downloadAllFabCoordinator = homeFabs!!.findViewById(R.id.download_all_coordinator)
|
||||
downloadSelectedFab = homeFabs!!.findViewById(R.id.download_selected_fab)
|
||||
downloadAllFab = homeFabs!!.findViewById(R.id.download_all_fab)
|
||||
clipboardFab = homeFabs!!.findViewById(R.id.copied_url_fab)
|
||||
|
||||
runCatching { materialToolbar!!.title = ThemeUtil.getStyledAppName(requireContext()) }
|
||||
|
||||
|
|
@ -160,6 +159,17 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
recyclerView?.adapter = homeAdapter
|
||||
recyclerView?.enableFastScroll()
|
||||
|
||||
|
||||
searchSuggestionsAdapter = SearchSuggestionsAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
searchSuggestionsRecyclerView = view.findViewById(R.id.search_suggestions_recycler)
|
||||
searchSuggestionsRecyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
searchSuggestionsRecyclerView?.adapter = searchSuggestionsAdapter
|
||||
searchSuggestionsRecyclerView?.enableFastScroll()
|
||||
|
||||
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
resultViewModel.items.observe(requireActivity()) {
|
||||
kotlin.runCatching {
|
||||
|
|
@ -167,9 +177,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
resultsList = it
|
||||
if(resultViewModel.repository.itemCount.value > 1 || resultViewModel.repository.itemCount.value == -1){
|
||||
if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && !loadingItems){
|
||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||
downloadAllFab!!.visibility = VISIBLE
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
downloadAllFab!!.visibility = GONE
|
||||
}
|
||||
}else if (resultViewModel.repository.itemCount.value == 1){
|
||||
if (sharedPreferences!!.getBoolean("download_card", true)){
|
||||
|
|
@ -181,20 +191,17 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
}
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
downloadAllFab!!.visibility = GONE
|
||||
}
|
||||
quickLaunchSheet = true
|
||||
}
|
||||
}
|
||||
|
||||
initMenu()
|
||||
val downloadSelectedFab = downloadFabs!!.findViewById<ExtendedFloatingActionButton>(R.id.download_selected_fab)
|
||||
downloadSelectedFab.tag = "downloadSelected"
|
||||
downloadSelectedFab.setOnClickListener(this)
|
||||
val downloadAllFab =
|
||||
downloadAllFabCoordinator!!.findViewById<ExtendedFloatingActionButton>(R.id.download_all_fab)
|
||||
downloadAllFab.tag = "downloadAll"
|
||||
downloadAllFab.setOnClickListener(this)
|
||||
downloadSelectedFab?.tag = "downloadSelected"
|
||||
downloadSelectedFab?.setOnClickListener(this)
|
||||
downloadAllFab?.tag = "downloadAll"
|
||||
downloadAllFab?.setOnClickListener(this)
|
||||
|
||||
if (arguments?.getString("url") != null){
|
||||
val url = requireArguments().getString("url")
|
||||
|
|
@ -247,9 +254,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
shimmerCards!!.stopShimmer()
|
||||
shimmerCards!!.visibility = GONE
|
||||
if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty()){
|
||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||
this@HomeFragment.downloadAllFab!!.visibility = VISIBLE
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
this@HomeFragment.downloadAllFab!!.visibility = GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -286,7 +293,18 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
|
||||
if (searchView?.currentTransitionState == SearchView.TransitionState.SHOWN){
|
||||
updateSearchViewItems(searchView?.editText?.text, linkYouCopied)
|
||||
updateSearchViewItems(searchView?.editText?.text)
|
||||
}
|
||||
|
||||
requireView().post {
|
||||
checkClipboard().apply {
|
||||
clipboardFab?.isVisible = this != null
|
||||
clipboardFab?.setOnClickListener {
|
||||
searchView!!.setText(this)
|
||||
clipboardFab?.isVisible = false
|
||||
initSearch(searchView!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,53 +357,13 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
chipGroupDivider?.visibility = VISIBLE
|
||||
}
|
||||
|
||||
try{
|
||||
val clipboard =
|
||||
requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = clipboard.primaryClip!!.getItemAt(0).text
|
||||
if (Patterns.WEB_URL.matcher(clip.toString()).matches()) {
|
||||
linkYouCopied!!.visibility = VISIBLE
|
||||
val textView = linkYouCopied!!.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = getString(R.string.link_you_copied)
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_language, 0, 0, 0)
|
||||
val mb = linkYouCopied!!.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setImageResource(R.drawable.ic_plus)
|
||||
|
||||
mb.setOnClickListener {
|
||||
val present = queriesChipGroup!!.children.firstOrNull { (it as Chip).text.toString() == clip.toString() }
|
||||
if (present == null) {
|
||||
val chip = layoutinflater!!.inflate(R.layout.input_chip, queriesChipGroup, false) as Chip
|
||||
chip.text = clip.toString()
|
||||
chip.chipBackgroundColor = ColorStateList.valueOf(MaterialColors.getColor(requireContext(), R.attr.colorSecondaryContainer, Color.BLACK))
|
||||
chip.setOnClickListener {
|
||||
queriesChipGroup!!.removeView(chip)
|
||||
}
|
||||
queriesChipGroup!!.addView(chip)
|
||||
}
|
||||
if (queriesChipGroup!!.childCount == 0) queriesConstraint.visibility = GONE
|
||||
else queriesConstraint.visibility = VISIBLE
|
||||
searchView!!.editText.setText("")
|
||||
linkYouCopied!!.visibility = GONE
|
||||
}
|
||||
|
||||
textView.setOnClickListener {
|
||||
searchView!!.setText(clip.toString())
|
||||
initSearch(searchView!!)
|
||||
}
|
||||
}else{
|
||||
linkYouCopied!!.visibility = GONE
|
||||
}
|
||||
updateSearchViewItems(searchView!!.editText.text, linkYouCopied)
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
linkYouCopied!!.visibility = GONE
|
||||
}
|
||||
updateSearchViewItems(searchView!!.editText.text)
|
||||
}
|
||||
}
|
||||
|
||||
searchView!!.editText.doAfterTextChanged {
|
||||
if (searchView!!.currentTransitionState != SearchView.TransitionState.SHOWN) return@doAfterTextChanged
|
||||
updateSearchViewItems(it, linkYouCopied)
|
||||
updateSearchViewItems(it)
|
||||
}
|
||||
|
||||
searchView!!.editText.setOnTouchListener(OnTouchListener { _, event ->
|
||||
|
|
@ -405,6 +383,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
chip.chipBackgroundColor = ColorStateList.valueOf(MaterialColors.getColor(requireContext(), R.attr.colorSecondaryContainer, Color.BLACK))
|
||||
chip.setOnClickListener {
|
||||
queriesChipGroup!!.removeView(chip)
|
||||
if (queriesChipGroup!!.childCount == 0) queriesConstraint.visibility = GONE
|
||||
}
|
||||
queriesChipGroup!!.addView(chip)
|
||||
}
|
||||
|
|
@ -430,12 +409,12 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
resultViewModel.getTrending()
|
||||
selectedObjects = ArrayList()
|
||||
searchBar!!.setText("")
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
downloadFabs!!.visibility = GONE
|
||||
downloadAllFab!!.visibility = GONE
|
||||
downloadSelectedFab!!.visibility = GONE
|
||||
}
|
||||
R.id.delete_search -> {
|
||||
resultViewModel.deleteAllSearchQueryHistory()
|
||||
searchSuggestionsLinearLayout!!.removeAllViews()
|
||||
searchSuggestionsAdapter?.submitList(listOf())
|
||||
}
|
||||
}
|
||||
true
|
||||
|
|
@ -451,26 +430,20 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
private fun updateSearchViewItems(searchQuery: Editable?, linkYouCopied: View?) = lifecycleScope.launch(Dispatchers.Main) {
|
||||
private fun updateSearchViewItems(searchQuery: Editable?) = lifecycleScope.launch(Dispatchers.Main) {
|
||||
lifecycleScope.launch {
|
||||
searchSuggestionsLinearLayout!!.visibility = GONE
|
||||
searchHistoryLinearLayout!!.visibility = GONE
|
||||
searchSuggestionsLinearLayout!!.post {
|
||||
searchSuggestionsLinearLayout!!.removeAllViews()
|
||||
}
|
||||
searchHistoryLinearLayout!!.post {
|
||||
searchHistoryLinearLayout!!.removeAllViews()
|
||||
}
|
||||
|
||||
linkYouCopied!!.visibility = GONE
|
||||
|
||||
if (searchView!!.editText.text.isEmpty()){
|
||||
searchView!!.editText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
|
||||
}else{
|
||||
searchView!!.editText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_plus, 0)
|
||||
}
|
||||
|
||||
val combinedList = mutableListOf<SearchSuggestionItem>()
|
||||
|
||||
val history = withContext(Dispatchers.IO){
|
||||
resultViewModel.getSearchHistory().map { it.query }.filter { it.contains(searchQuery!!) }
|
||||
}.map {
|
||||
SearchSuggestionItem(it, SearchSuggestionType.HISTORY)
|
||||
}
|
||||
val suggestions = if (sharedPreferences!!.getBoolean("search_suggestions", false)){
|
||||
withContext(Dispatchers.IO){
|
||||
|
|
@ -478,66 +451,80 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
}else{
|
||||
emptyList()
|
||||
}.map {
|
||||
SearchSuggestionItem(it, SearchSuggestionType.SUGGESTION)
|
||||
}
|
||||
|
||||
history.forEach { s ->
|
||||
val v = LayoutInflater.from(fragmentContext).inflate(R.layout.search_suggestion_item, null)
|
||||
val textView = v.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = s
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
searchHistoryLinearLayout!!.addView(
|
||||
v
|
||||
)
|
||||
}
|
||||
textView.setOnClickListener {
|
||||
searchView!!.setText(s)
|
||||
initSearch(searchView!!)
|
||||
}
|
||||
textView.setOnLongClickListener {
|
||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + s + "\"!")
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
searchHistoryLinearLayout!!.removeView(v)
|
||||
resultViewModel.removeSearchQueryFromHistory(s)
|
||||
}
|
||||
deleteDialog.show()
|
||||
true
|
||||
}
|
||||
combinedList.addAll(history)
|
||||
combinedList.addAll(suggestions)
|
||||
|
||||
val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setOnClickListener {
|
||||
searchView!!.editText.setText(s)
|
||||
searchView!!.editText.setSelection(searchView!!.editText.length())
|
||||
}
|
||||
}
|
||||
searchHistoryLinearLayout!!.isVisible = history.isNotEmpty()
|
||||
if (linkYouCopied.findViewById<TextView>(R.id.suggestion_text).text.isNotEmpty()){
|
||||
linkYouCopied.visibility = VISIBLE
|
||||
val url = checkClipboard()
|
||||
url?.apply {
|
||||
combinedList.add(0, SearchSuggestionItem(this, SearchSuggestionType.CLIPBOARD))
|
||||
}
|
||||
|
||||
suggestions.forEach { s ->
|
||||
val v = LayoutInflater.from(fragmentContext)
|
||||
.inflate(R.layout.search_suggestion_item, null)
|
||||
val textView = v.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = s
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
searchSuggestionsLinearLayout!!.addView(
|
||||
v
|
||||
)
|
||||
}
|
||||
textView.setOnClickListener {
|
||||
searchView!!.setText(s)
|
||||
initSearch(searchView!!)
|
||||
}
|
||||
val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setOnClickListener {
|
||||
searchView!!.editText.setText(s)
|
||||
searchView!!.editText.setSelection(searchView!!.editText.length())
|
||||
}
|
||||
}
|
||||
searchSuggestionsLinearLayout!!.isVisible = suggestions.isNotEmpty()
|
||||
|
||||
searchSuggestionsAdapter?.submitList(combinedList)
|
||||
|
||||
// history.forEach { s ->
|
||||
// val v = LayoutInflater.from(fragmentContext).inflate(R.layout.search_suggestion_item, null)
|
||||
// val textView = v.findViewById<TextView>(R.id.suggestion_text)
|
||||
// textView.text = s
|
||||
// textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0)
|
||||
// Handler(Looper.getMainLooper()).post {
|
||||
// searchHistoryLinearLayout!!.addView(
|
||||
// v
|
||||
// )
|
||||
// }
|
||||
// textView.setOnClickListener {
|
||||
// searchView!!.setText(s)
|
||||
// initSearch(searchView!!)
|
||||
// }
|
||||
// textView.setOnLongClickListener {
|
||||
// val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
// deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + s + "\"!")
|
||||
// deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
// deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
// searchHistoryLinearLayout!!.removeView(v)
|
||||
// resultViewModel.removeSearchQueryFromHistory(s)
|
||||
// }
|
||||
// deleteDialog.show()
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
// mb.setOnClickListener {
|
||||
// searchView!!.editText.setText(s)
|
||||
// searchView!!.editText.setSelection(searchView!!.editText.length())
|
||||
// }
|
||||
// }
|
||||
// searchHistoryLinearLayout!!.isVisible = history.isNotEmpty()
|
||||
// if (linkYouCopied.findViewById<TextView>(R.id.suggestion_text).text.isNotEmpty()){
|
||||
// linkYouCopied.visibility = VISIBLE
|
||||
// clipboardFab?.isVisible = true
|
||||
// }
|
||||
//
|
||||
// suggestions.forEach { s ->
|
||||
// val v = LayoutInflater.from(fragmentContext)
|
||||
// .inflate(R.layout.search_suggestion_item, null)
|
||||
// val textView = v.findViewById<TextView>(R.id.suggestion_text)
|
||||
// textView.text = s
|
||||
// Handler(Looper.getMainLooper()).post {
|
||||
// searchSuggestionsLinearLayout!!.addView(
|
||||
// v
|
||||
// )
|
||||
// }
|
||||
// textView.setOnClickListener {
|
||||
// searchView!!.setText(s)
|
||||
// initSearch(searchView!!)
|
||||
// }
|
||||
// val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
// mb.setOnClickListener {
|
||||
// searchView!!.editText.setText(s)
|
||||
// searchView!!.editText.setSelection(searchView!!.editText.length())
|
||||
// }
|
||||
// }
|
||||
// searchSuggestionsLinearLayout!!.isVisible = suggestions.isNotEmpty()
|
||||
|
||||
if (Patterns.WEB_URL.matcher(searchView!!.editText.text).matches()){
|
||||
providersChipGroup?.visibility = GONE
|
||||
|
|
@ -637,6 +624,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
showSingleDownloadSheet(item!!, type!!)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private fun showSingleDownloadSheet(
|
||||
resultItem: ResultItem,
|
||||
type: DownloadViewModel.Type
|
||||
|
|
@ -807,6 +795,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
|
||||
|
||||
private fun checkClipboard(): String?{
|
||||
return kotlin.runCatching {
|
||||
val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = clipboard.primaryClip!!.getItemAt(0).text
|
||||
val matchesURL = Patterns.WEB_URL.matcher(clip.toString()).matches()
|
||||
return if (matchesURL) clip.toString() else null
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
actionMode?.finish()
|
||||
super.onStop()
|
||||
|
|
@ -816,4 +813,49 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
companion object {
|
||||
private const val TAG = "HomeFragment"
|
||||
}
|
||||
|
||||
override fun onSearchSuggestionClick(text: String) {
|
||||
clipboardFab?.isVisible = false
|
||||
searchView!!.setText(text)
|
||||
initSearch(searchView!!)
|
||||
}
|
||||
|
||||
override fun onSearchSuggestionAdd(text: String) {
|
||||
val present = queriesChipGroup!!.children.firstOrNull { (it as Chip).text.toString() == text }
|
||||
if (present == null) {
|
||||
val chip = layoutinflater!!.inflate(R.layout.input_chip, queriesChipGroup, false) as Chip
|
||||
chip.text = text
|
||||
chip.chipBackgroundColor = ColorStateList.valueOf(MaterialColors.getColor(requireContext(), R.attr.colorSecondaryContainer, Color.BLACK))
|
||||
chip.setOnClickListener {
|
||||
queriesChipGroup!!.removeView(chip)
|
||||
if (queriesChipGroup!!.childCount == 0) queriesChipGroup!!.visibility = View.GONE
|
||||
}
|
||||
queriesChipGroup!!.addView(chip)
|
||||
}
|
||||
if (queriesChipGroup!!.childCount == 0) queriesConstraint!!.visibility = View.GONE
|
||||
else queriesConstraint!!.visibility = View.VISIBLE
|
||||
searchView!!.editText.setText("")
|
||||
val clipBoardItem = searchSuggestionsRecyclerView?.layoutManager?.findViewByPosition(0)
|
||||
clipBoardItem?.apply {
|
||||
if ((this as ConstraintLayout).findViewById<TextView>(R.id.suggestion_text).text == getString(R.string.link_you_copied)){
|
||||
searchSuggestionsAdapter?.notifyItemRemoved(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSearchSuggestionLongClick(text: String, position: Int) {
|
||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + text + "\"!")
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
resultViewModel.removeSearchQueryFromHistory(text)
|
||||
searchSuggestionsAdapter?.notifyItemRemoved(position)
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
|
||||
override fun onSearchSuggestionAddToSearchBar(text: String) {
|
||||
searchView!!.editText.setText(text)
|
||||
searchView!!.editText.setSelection(searchView!!.editText.length())
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,13 @@ import android.graphics.ColorMatrix
|
|||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
|
|
@ -23,7 +24,11 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.badge.BadgeUtils
|
||||
import com.google.android.material.badge.ExperimentalBadgeUtils
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.squareup.picasso.Picasso
|
||||
import java.io.File
|
||||
|
|
@ -54,10 +59,28 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryAdapter.ViewHolder {
|
||||
return if (viewType == 0){
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
ViewHolder(cardView, onItemClickListener)
|
||||
}else{
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card_multiple, parent, false)
|
||||
ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
getItem(position)?.apply {
|
||||
return if(this.downloadPath.size == 1){
|
||||
0
|
||||
}else{
|
||||
1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
|
|
@ -82,7 +105,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
||||
var title = item!!.title
|
||||
var title = item!!.title.ifEmpty { item.url }
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
|
|
@ -98,44 +121,38 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
|
||||
// TIME DOWNLOADED ----------------------------------
|
||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
||||
|
||||
// val relativeTime = DateUtils.getRelativeTimeSpanString(
|
||||
// item.time * 1000L,
|
||||
// System.currentTimeMillis(),
|
||||
// DateUtils.MINUTE_IN_MILLIS
|
||||
// )
|
||||
datetime.text = SimpleDateFormat(android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L)
|
||||
|
||||
// BUTTON ----------------------------------
|
||||
val btn = card.findViewById<FloatingActionButton>(R.id.downloads_download_button_type)
|
||||
var filePresent = true
|
||||
var filesPresent = true
|
||||
|
||||
//IS IN THE FILE SYSTEM?
|
||||
val path = item.downloadPath
|
||||
val file = File(path)
|
||||
if (!file.exists() && path.isNotEmpty()) {
|
||||
filePresent = false
|
||||
if (item.downloadPath.all { !File(it).exists() && it.isNotBlank()}) {
|
||||
filesPresent = false
|
||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
||||
init {
|
||||
setSaturation(0f)
|
||||
}
|
||||
})
|
||||
thumbnail.alpha = 0.7f
|
||||
btn.backgroundTintList = ContextCompat.getColorStateList(activity, R.color.black)
|
||||
btn.imageTintList = ContextCompat.getColorStateList(activity, R.color.white)
|
||||
btn.backgroundTintList = MaterialColors.getColorStateList(activity, R.attr.colorSurface, ContextCompat.getColorStateList(activity, android.R.color.transparent)!!)
|
||||
}else{
|
||||
thumbnail.alpha = 1f
|
||||
btn.backgroundTintList = MaterialColors.getColorStateList(activity, R.attr.colorPrimaryContainer, ContextCompat.getColorStateList(activity, android.R.color.transparent)!!)
|
||||
}
|
||||
|
||||
if (item.type == DownloadViewModel.Type.audio) {
|
||||
if (filePresent) btn.setImageResource(R.drawable.ic_music_downloaded) else {
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_music_downloaded) else {
|
||||
btn.setImageResource(R.drawable.ic_music)
|
||||
}
|
||||
} else if (item.type == DownloadViewModel.Type.video) {
|
||||
if (filePresent) btn.setImageResource(R.drawable.ic_video_downloaded) else btn.setImageResource(R.drawable.ic_video)
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_video_downloaded) else btn.setImageResource(R.drawable.ic_video)
|
||||
}else{
|
||||
if (filePresent) btn.setImageResource(R.drawable.ic_terminal) else btn.setImageResource(R.drawable.baseline_code_off_24)
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_terminal) else btn.setImageResource(R.drawable.baseline_code_off_24)
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
btn.isClickable = filePresent
|
||||
btn.isClickable = filesPresent
|
||||
|
||||
if (checkedItems.contains(item.id)) {
|
||||
card.isChecked = true
|
||||
|
|
@ -144,7 +161,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
card.isChecked = false
|
||||
card.strokeWidth = 0
|
||||
}
|
||||
val finalFilePresent = filePresent
|
||||
val finalFilePresent = filesPresent
|
||||
card.setOnLongClickListener {
|
||||
checkCard(card, item.id)
|
||||
true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
package com.deniscerri.ytdlnis.ui.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.SearchSuggestionItem
|
||||
import com.deniscerri.ytdlnis.database.models.SearchSuggestionType
|
||||
|
||||
|
||||
class SearchSuggestionsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<SearchSuggestionItem, SearchSuggestionsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||
DIFF_CALLBACK
|
||||
).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private val sharedPreferences: SharedPreferences
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val linear: LinearLayout
|
||||
|
||||
init {
|
||||
linear = itemView.findViewById(R.id.linear)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchSuggestionsAdapter.ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.search_suggestion_item, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position) ?: return
|
||||
val linear = holder.linear
|
||||
when (item.type){
|
||||
SearchSuggestionType.SUGGESTION -> {
|
||||
val textView = linear.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = item.text
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_search, 0, 0, 0)
|
||||
|
||||
textView.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionClick(item.text)
|
||||
}
|
||||
textView.setOnLongClickListener { true }
|
||||
val mb = linear.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionAddToSearchBar(item.text)
|
||||
}
|
||||
}
|
||||
SearchSuggestionType.HISTORY -> {
|
||||
val textView = linear.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = item.text
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0)
|
||||
textView.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionClick(item.text)
|
||||
}
|
||||
textView.setOnLongClickListener {
|
||||
onItemClickListener.onSearchSuggestionLongClick(item.text, position)
|
||||
true
|
||||
}
|
||||
|
||||
val mb = linear.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionAddToSearchBar(item.text)
|
||||
}
|
||||
}
|
||||
SearchSuggestionType.CLIPBOARD -> {
|
||||
val textView = linear.findViewById<TextView>(R.id.suggestion_text)
|
||||
textView.text = activity.getString(R.string.link_you_copied)
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_language, 0, 0, 0)
|
||||
val mb = linear.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.setImageResource(R.drawable.ic_plus)
|
||||
|
||||
mb.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionAdd(item.text)
|
||||
}
|
||||
|
||||
textView.setOnClickListener {
|
||||
onItemClickListener.onSearchSuggestionClick(item.text)
|
||||
}
|
||||
textView.setOnLongClickListener { true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onSearchSuggestionClick(text: String)
|
||||
fun onSearchSuggestionAdd(text: String)
|
||||
|
||||
fun onSearchSuggestionLongClick(text: String, position: Int)
|
||||
|
||||
fun onSearchSuggestionAddToSearchBar(text: String)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<SearchSuggestionItem> = object : DiffUtil.ItemCallback<SearchSuggestionItem>() {
|
||||
override fun areItemsTheSame(oldItem: SearchSuggestionItem, newItem: SearchSuggestionItem): Boolean {
|
||||
return oldItem.text == newItem.text && oldItem.type == newItem.type
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: SearchSuggestionItem, newItem: SearchSuggestionItem): Boolean {
|
||||
return oldItem.text == newItem.text && oldItem.type == newItem.type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
|
|||
putString("last_used_download_type",
|
||||
listOf(Type.audio, Type.video, Type.command)[position].toString())
|
||||
}
|
||||
updateTitleAuthorWhenSwitching()
|
||||
updateWhenSwitching()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -205,7 +205,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
|
|||
}
|
||||
|
||||
|
||||
private fun updateTitleAuthorWhenSwitching(){
|
||||
private fun updateWhenSwitching(){
|
||||
val prevDownloadItem = getDownloadItem(
|
||||
if (viewPager2.currentItem == 1) 0 else 1
|
||||
)
|
||||
|
|
@ -223,6 +223,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
|
|||
1 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
f.updateSelectedAudioFormat(getDownloadItem(0).format)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
|||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
genericAudioFormats = infoUtil.getGenericAudioFormats(requireContext().resources)
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
|
@ -295,7 +295,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
|||
updateDataClicked = {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
resultItem?.apply {
|
||||
resultViewModel.updateItemData(this)
|
||||
val rsVM = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
|
||||
rsVM.updateItemData(this)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,29 +9,25 @@ import android.os.Build
|
|||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.Player.Command
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
|
|
@ -246,6 +242,9 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
if (tab!!.position == 2 && commandTemplateNr == 0){
|
||||
tabLayout.selectTab(tabLayout.getTabAt(1))
|
||||
val s = Snackbar.make(view, getString(R.string.add_template_first), Snackbar.LENGTH_LONG)
|
||||
val snackbarView: View = s.view
|
||||
val snackTextView = snackbarView.findViewById<View>(com.google.android.material.R.id.snackbar_text) as TextView
|
||||
snackTextView.maxLines = 9999999
|
||||
s.setAction(R.string.new_template){
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(item = null, context = requireActivity(), lifeCycle = this@DownloadBottomSheetDialog, commandTemplateViewModel = commandTemplateViewModel){
|
||||
commandTemplateNr = 1
|
||||
|
|
@ -279,7 +278,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
putString("last_used_download_type",
|
||||
listOf(Type.audio, Type.video, Type.command)[position].toString())
|
||||
}
|
||||
updateTitleAuthorWhenSwitching()
|
||||
updateWhenSwitching()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -437,6 +436,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
shimmerLoadingSubtitle.visibility = View.VISIBLE
|
||||
shimmerLoading.startShimmer()
|
||||
shimmerLoadingSubtitle.startShimmer()
|
||||
updateItem.visibility = View.GONE
|
||||
}else{
|
||||
title.visibility = View.VISIBLE
|
||||
subtitle.visibility = View.VISIBLE
|
||||
|
|
@ -600,7 +600,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateTitleAuthorWhenSwitching(){
|
||||
private fun updateWhenSwitching(){
|
||||
val prevDownloadItem = getDownloadItem(
|
||||
if (viewPager2.currentItem == 1) 0 else 1
|
||||
)
|
||||
|
|
@ -617,6 +617,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
kotlin.runCatching {
|
||||
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
f.updateSelectedAudioFormat(getDownloadItem(0).format)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.util.Patterns
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
|
@ -123,6 +124,13 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
}
|
||||
})
|
||||
|
||||
chosenCommandView.editText!!.setSelection(chosenCommandView.editText!!.text.length)
|
||||
val imm = context?.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
chosenCommandView.editText!!.postDelayed({
|
||||
chosenCommandView.editText!!.requestFocus()
|
||||
imm.showSoftInput(chosenCommandView.editText, 0)
|
||||
}, 300)
|
||||
|
||||
chosenCommandView.setEndIconOnClickListener {
|
||||
if(chosenCommandView.editText!!.text.isEmpty()){
|
||||
val clipboard: ClipboardManager =
|
||||
|
|
@ -252,8 +260,9 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
shortcutClicked = {
|
||||
UiUtil.showShortcuts(requireActivity(), commandTemplateViewModel,
|
||||
itemSelected = {
|
||||
chosenCommandView.editText!!.setText("${chosenCommandView.editText!!.text} $it")
|
||||
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString()
|
||||
val selectionStart = chosenCommandView.editText!!.selectionStart
|
||||
chosenCommandView.editText!!.text.insert(selectionStart, it)
|
||||
chosenCommandView.editText!!.setSelection(selectionStart + it.length)
|
||||
preferences.edit().putString("lastCommandTemplateUsed", downloadItem.format.format_note).apply()
|
||||
},
|
||||
itemRemoved = {removed ->
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import androidx.work.Data
|
|||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.ui.adapter.ConfigureMultipleDownloadsAdapter
|
||||
|
|
@ -136,7 +137,9 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
|||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
recyclerView.adapter = listAdapter
|
||||
recyclerView.enableFastScroll()
|
||||
if(sharedPreferences.getBoolean("swipe_gestures", true)){
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
if (preferences.getStringSet("swipe_gesture", requireContext().getStringArray(R.array.swipe_gestures_values).toSet())!!.toList().contains("multipledownloadcard")){
|
||||
val itemTouchHelper = ItemTouchHelper(simpleCallback)
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView)
|
||||
}
|
||||
|
|
@ -603,7 +606,8 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
|||
items.forEach {
|
||||
it.downloadPath = result.data?.data.toString()
|
||||
}
|
||||
Toast.makeText(requireContext(), "Changed every item's download path to: ${FileUtil.formatPath(result.data!!.data.toString())}", Toast.LENGTH_LONG).show()
|
||||
val path = FileUtil.formatPath(result.data!!.data.toString())
|
||||
Snackbar.make(requireView(),getString(R.string.changed_path_for_everyone_to) + " " + path, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.fragment_download_video, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
genericVideoFormats = infoUtil.getGenericVideoFormats(requireContext().resources)
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
|
@ -218,8 +218,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
downloadItem.videoPreferences.audioFormatIDs.clear()
|
||||
downloadItem.videoPreferences.audioFormatIDs.addAll(it)
|
||||
}
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, item.first().format, item.first().audioFormats)
|
||||
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, item.first().format,
|
||||
if(downloadItem.videoPreferences.removeAudio) listOf() else item.first().audioFormats
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFormatsUpdated(allFormats: List<List<Format>>) {
|
||||
|
|
@ -241,7 +242,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
val preferredAudioFormats = downloadViewModel.getPreferredAudioFormats(formats)
|
||||
downloadItem.format = preferredFormat
|
||||
downloadItem.allFormats = formats
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat, formats.filter { preferredAudioFormats.contains(it.format_id) })
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat,
|
||||
if(downloadItem.videoPreferences.removeAudio) listOf() else formats.filter { preferredAudioFormats.contains(it.format_id) }
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -315,7 +318,8 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
updateDataClicked = {
|
||||
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO) {
|
||||
resultItem?.apply {
|
||||
resultViewModel.updateItemData(this)
|
||||
val rsVM = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
|
||||
rsVM.updateItemData(this)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -330,6 +334,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
},
|
||||
removeAudioClicked = {
|
||||
downloadItem.videoPreferences.removeAudio = it
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, if (it) listOf() else downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) })
|
||||
},
|
||||
extraCommandsClicked = {
|
||||
val callback = object : ExtraCommandsListener {
|
||||
|
|
@ -366,6 +371,16 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
onViewCreated(requireView(),savedInstanceState = state)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun updateSelectedAudioFormat(format: Format){
|
||||
downloadItem.videoPreferences.audioFormatIDs.clear()
|
||||
downloadItem.videoPreferences.audioFormatIDs.addAll(arrayListOf(format.format_id))
|
||||
val formatCard = requireView().findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
|
||||
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format,
|
||||
if(downloadItem.videoPreferences.removeAudio) listOf() else listOf(format)
|
||||
)
|
||||
}
|
||||
|
||||
private var pathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
|
|
|
|||
|
|
@ -7,22 +7,31 @@ import android.os.Bundle
|
|||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.*
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.facebook.shimmer.ShimmerFrameLayout
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -35,10 +44,11 @@ import java.util.*
|
|||
class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, private var formats: List<List<Format>>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var formatCollection: MutableList<List<Format>>
|
||||
private lateinit var chosenFormats: List<Format>
|
||||
private lateinit var selectedVideo : Format
|
||||
private var selectedVideo : Format? = null
|
||||
private lateinit var selectedAudios : MutableList<Format>
|
||||
|
||||
private lateinit var videoFormatList : LinearLayout
|
||||
|
|
@ -48,15 +58,23 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
private lateinit var audioTitle : TextView
|
||||
|
||||
private lateinit var sortBy : FormatSorting
|
||||
private lateinit var filterBy : FormatCategory
|
||||
private lateinit var filterBtn : Button
|
||||
|
||||
private lateinit var continueInBackgroundSnackBar : Snackbar
|
||||
private lateinit var view: View
|
||||
private var updateFormatsJob: Job? = null
|
||||
|
||||
private var hasGenericFormats: Boolean = false
|
||||
|
||||
enum class FormatSorting {
|
||||
filesize, container, codec, id
|
||||
}
|
||||
|
||||
enum class FormatCategory {
|
||||
ALL, SUGGESTED, SMALLEST, GENERIC
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
|
|
@ -64,6 +82,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
chosenFormats = listOf()
|
||||
selectedAudios = mutableListOf()
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -74,6 +93,8 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
dialog.setContentView(view)
|
||||
|
||||
sortBy = FormatSorting.valueOf(sharedPreferences.getString("format_order", "filesize")!!)
|
||||
filterBy = FormatCategory.valueOf(sharedPreferences.getString("format_filter", "ALL")!!)
|
||||
filterBtn = view.findViewById(R.id.format_filter)
|
||||
|
||||
dialog.setOnShowListener {
|
||||
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||
|
|
@ -92,7 +113,9 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
okBtn = view.findViewById(R.id.format_ok)
|
||||
|
||||
shimmers.visibility = View.GONE
|
||||
val hasGenericFormats = formats.first().isEmpty() || formats.last().any { it.format_id == "best" || it.format_id == "ba" }
|
||||
hasGenericFormats = formats.first().isEmpty() || formats.last().any { it.format_id == "best" || it.format_id == "ba" }
|
||||
filterBtn.isVisible = !hasGenericFormats
|
||||
|
||||
if (items.size > 1){
|
||||
|
||||
if (!hasGenericFormats){
|
||||
|
|
@ -140,16 +163,18 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
|
||||
|
||||
chosenFormats = emptyList()
|
||||
try {
|
||||
refreshBtn.isEnabled = false
|
||||
formatListLinearLayout.visibility = View.GONE
|
||||
shimmers.visibility = View.VISIBLE
|
||||
shimmers.startShimmer()
|
||||
updateFormatsJob = launch(Dispatchers.IO) {
|
||||
refreshBtn.isEnabled = false
|
||||
formatListLinearLayout.visibility = View.GONE
|
||||
shimmers.visibility = View.VISIBLE
|
||||
shimmers.startShimmer()
|
||||
updateFormatsJob = launch {
|
||||
try{
|
||||
//simple download
|
||||
if (items.size == 1) {
|
||||
kotlin.runCatching {
|
||||
val res = infoUtil.getFormats(items.first()!!.url)
|
||||
val res = withContext(Dispatchers.IO){
|
||||
infoUtil.getFormats(items.first()!!.url)
|
||||
}
|
||||
res.filter { it.format_note != "storyboard" }
|
||||
chosenFormats = if (items.first()?.type == Type.audio) {
|
||||
res.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
|
|
@ -172,19 +197,21 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
}
|
||||
|
||||
//list format filtering
|
||||
//list format filtering
|
||||
}else{
|
||||
var progress = "0/${items.size}"
|
||||
formatCollection.clear()
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshBtn.text = progress
|
||||
}
|
||||
infoUtil.getFormatsMultiple(items.map { it!!.url }) {
|
||||
if (isActive) {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
formatCollection.add(it)
|
||||
progress = "${formatCollection.size}/${items.size}"
|
||||
refreshBtn.text = progress
|
||||
withContext(Dispatchers.IO){
|
||||
infoUtil.getFormatsMultiple(items.map { it!!.url }) {
|
||||
if (isActive) {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
formatCollection.add(it)
|
||||
progress = "${formatCollection.size}/${items.size}"
|
||||
refreshBtn.text = progress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,32 +245,34 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
.sumOf { itt -> itt.filesize }
|
||||
}
|
||||
}
|
||||
hasGenericFormats = false
|
||||
withContext(Dispatchers.Main){
|
||||
shimmers.visibility = View.GONE
|
||||
shimmers.stopShimmer()
|
||||
filterBtn.isVisible = true
|
||||
addFormatsToView()
|
||||
refreshBtn.visibility = View.GONE
|
||||
formatListLinearLayout.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
updateFormatsJob?.start()
|
||||
}catch (e: Exception){
|
||||
runCatching {
|
||||
refreshBtn.isEnabled = true
|
||||
refreshBtn.text = getString(R.string.update_formats)
|
||||
formatListLinearLayout.visibility = View.VISIBLE
|
||||
shimmers.visibility = View.GONE
|
||||
shimmers.stopShimmer()
|
||||
}catch (e: Exception){
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshBtn.isEnabled = true
|
||||
refreshBtn.text = getString(R.string.update_formats)
|
||||
formatListLinearLayout.visibility = View.VISIBLE
|
||||
shimmers.visibility = View.GONE
|
||||
shimmers.stopShimmer()
|
||||
|
||||
e.printStackTrace()
|
||||
Toast.makeText(context, getString(R.string.error_updating_formats), Toast.LENGTH_SHORT).show()
|
||||
e.printStackTrace()
|
||||
Toast.makeText(context, getString(R.string.error_updating_formats), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
updateFormatsJob?.start()
|
||||
}
|
||||
}
|
||||
|
||||
okBtn.setOnClickListener {
|
||||
if (!::selectedVideo.isInitialized) {
|
||||
if (selectedVideo == null) {
|
||||
selectedVideo =
|
||||
chosenFormats.filter { it.vcodec.isNotBlank() && it.vcodec != "none" }.maxByOrNull { it.filesize }!!
|
||||
}
|
||||
|
|
@ -254,21 +283,85 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
// if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
|
||||
// refreshBtn.performClick()
|
||||
// }
|
||||
|
||||
initFilter()
|
||||
}
|
||||
|
||||
|
||||
private fun initFilter(){
|
||||
filterBtn.setOnClickListener {
|
||||
val filterSheet = BottomSheetDialog(requireContext())
|
||||
filterSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
filterSheet.setContentView(R.layout.format_category_sheet)
|
||||
|
||||
val all = filterSheet.findViewById<TextView>(R.id.all)
|
||||
val suggested = filterSheet.findViewById<TextView>(R.id.suggested)
|
||||
val smallest = filterSheet.findViewById<TextView>(R.id.smallest)
|
||||
val generic = filterSheet.findViewById<TextView>(R.id.generic)
|
||||
|
||||
val filterOptions = listOf(all!!, suggested!!,smallest!!, generic!!)
|
||||
filterOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
when(filterBy) {
|
||||
FormatCategory.ALL -> all.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
FormatCategory.SUGGESTED -> {
|
||||
suggested.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
}
|
||||
FormatCategory.SMALLEST -> {
|
||||
smallest.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
}
|
||||
FormatCategory.GENERIC -> {
|
||||
generic.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
}
|
||||
}
|
||||
|
||||
all.setOnClickListener {
|
||||
filterOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
filterBy = FormatCategory.ALL
|
||||
all.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
addFormatsToView()
|
||||
filterSheet.dismiss()
|
||||
}
|
||||
suggested.setOnClickListener {
|
||||
filterOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
filterBy = FormatCategory.SUGGESTED
|
||||
suggested.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
addFormatsToView()
|
||||
filterSheet.dismiss()
|
||||
}
|
||||
smallest.setOnClickListener {
|
||||
filterOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
filterBy = FormatCategory.SMALLEST
|
||||
smallest.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
addFormatsToView()
|
||||
filterSheet.dismiss()
|
||||
}
|
||||
generic.setOnClickListener {
|
||||
filterOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
filterBy = FormatCategory.GENERIC
|
||||
generic.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_check, 0,0,0)
|
||||
addFormatsToView()
|
||||
filterSheet.dismiss()
|
||||
}
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
filterSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
filterSheet.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnFormats(){
|
||||
//simple video format selection
|
||||
if (items.size == 1){
|
||||
listener.onFormatClick(listOf(FormatTuple(selectedVideo, selectedAudios)))
|
||||
listener.onFormatClick(listOf(FormatTuple(selectedVideo!!, selectedAudios.ifEmpty { listOf(downloadViewModel.getFormat(chosenFormats, Type.audio)) })))
|
||||
}else{
|
||||
//playlist format selection
|
||||
val selectedFormats = mutableListOf<Format>()
|
||||
formatCollection.forEach {
|
||||
selectedFormats.add(it.first{ f -> f.format_id == selectedVideo.format_id})
|
||||
selectedFormats.add(it.first{ f -> f.format_id == selectedVideo!!.format_id})
|
||||
}
|
||||
if (selectedFormats.isEmpty()) {
|
||||
items.forEach { _ ->
|
||||
selectedFormats.add(selectedVideo)
|
||||
selectedFormats.add(selectedVideo!!)
|
||||
}
|
||||
}
|
||||
listener.onFormatClick(selectedFormats.map { FormatTuple(it, selectedAudios) })
|
||||
|
|
@ -292,6 +385,53 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
FormatSorting.filesize -> chosenFormats
|
||||
}
|
||||
|
||||
//filter category
|
||||
when(filterBy){
|
||||
FormatCategory.ALL -> {}
|
||||
FormatCategory.SUGGESTED -> {
|
||||
finalFormats = if (items.first()?.type == Type.audio){
|
||||
val req = downloadViewModel.getPreferredAudioRequirements()
|
||||
finalFormats
|
||||
.filter { f -> req.count{req -> req(f)} >= 1 }
|
||||
.sortedByDescending { f -> req.count{req -> req(f)} }
|
||||
.ifEmpty { listOf(downloadViewModel.getFormat(finalFormats, Type.audio)) }
|
||||
}else{
|
||||
val req = downloadViewModel.getPreferredVideoRequirements()
|
||||
req.addAll(downloadViewModel.getPreferredAudioRequirements())
|
||||
finalFormats
|
||||
.filter { f -> req.count{req -> req(f)} >= 1 }
|
||||
.sortedByDescending { f -> req.count{req -> req(f)} }
|
||||
.ifEmpty { listOf(downloadViewModel.getFormat(finalFormats, Type.video)) }
|
||||
}
|
||||
}
|
||||
FormatCategory.SMALLEST -> {
|
||||
val tmpFormats = finalFormats
|
||||
.asSequence()
|
||||
.map { it.copy() }
|
||||
.filter { it.filesize > 0 }
|
||||
.onEach {
|
||||
var tmp = it.format_note
|
||||
//formats that end like 1080P
|
||||
if (tmp.endsWith("060")){
|
||||
tmp = tmp.removeSuffix("60")
|
||||
}
|
||||
tmp = tmp.removeSuffix("p")
|
||||
//formats that are written like 1920X1080
|
||||
val split = tmp.split("x")
|
||||
if (split.size > 1){
|
||||
tmp = split[1]
|
||||
}
|
||||
it.format_note = tmp
|
||||
}
|
||||
.groupBy { it.format_note }
|
||||
.map { it.value.minBy { it2 -> it2.filesize } }.toList()
|
||||
finalFormats = finalFormats.filter { tmpFormats.map { it2 -> it2.format_id }.contains(it.format_id) }
|
||||
}
|
||||
FormatCategory.GENERIC -> {
|
||||
finalFormats = listOf()
|
||||
}
|
||||
}
|
||||
|
||||
val canMultiSelectAudio = items.first()?.type == Type.video && finalFormats.find { it.format_note.contains("audio", ignoreCase = true) } != null
|
||||
videoFormatList.removeAllViews()
|
||||
audioFormatList.removeAllViews()
|
||||
|
|
@ -315,6 +455,10 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
videoFormatList.removeAllViews()
|
||||
audioFormatList.removeAllViews()
|
||||
|
||||
if (finalFormats.isEmpty()){
|
||||
finalFormats = if (items.first()?.type == Type.audio){
|
||||
infoUtil.getGenericAudioFormats(requireContext().resources)
|
||||
|
|
@ -328,6 +472,8 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null)
|
||||
formatItem.tag = "${format.format_id}${format.format_note}"
|
||||
UiUtil.populateFormatCard(requireContext(), formatItem as MaterialCardView, format, null)
|
||||
if (selectedVideo == format) formatItem.isChecked = true
|
||||
if (selectedAudios.any { it == format }) formatItem.isChecked = true
|
||||
formatItem.setOnClickListener{ clickedformat ->
|
||||
//if the context is behind a video or playlist, allow the ability to multiselect audio formats
|
||||
if (canMultiSelectAudio){
|
||||
|
|
@ -380,6 +526,31 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}else{
|
||||
videoFormatList.addView(formatItem)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (items.first()?.type == Type.video){
|
||||
selectedVideo = null
|
||||
run breaking@{
|
||||
videoFormatList.children.forEach {
|
||||
val card = it as MaterialCardView
|
||||
if (card.isChecked){
|
||||
selectedVideo = finalFormats.first { format -> "${format.format_id}${format.format_note}" == card.tag }
|
||||
return@breaking
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
selectedAudios = mutableListOf()
|
||||
run breaking@{
|
||||
audioFormatList.children.forEach {
|
||||
val card = it as MaterialCardView
|
||||
if (card.isChecked){
|
||||
selectedAudios.add(finalFormats.first { format -> "${format.format_id}${format.format_note}" == card.tag })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
|
|
@ -103,6 +104,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
return fragmentView
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -519,7 +521,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
true
|
||||
}
|
||||
R.id.share -> {
|
||||
UiUtil.shareFileIntent(requireContext(), selectedObjects!!.map { it.downloadPath })
|
||||
UiUtil.shareFileIntent(requireContext(), selectedObjects!!.map { it.downloadPath }.flatten())
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
true
|
||||
|
|
@ -633,7 +635,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
override fun onButtonClick(itemID: Long, isPresent: Boolean) {
|
||||
if (isPresent){
|
||||
UiUtil.shareFileIntent(requireContext(), listOf(historyList!!.first { it!!.id == itemID }!!.downloadPath))
|
||||
UiUtil.shareFileIntent(requireContext(), historyList!!.first { it!!.id == itemID }!!.downloadPath)
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -4,42 +4,32 @@ import android.annotation.SuppressLint
|
|||
import android.app.ActionBar
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.method.MovementMethod
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||
import com.deniscerri.ytdlnis.util.Extensions.enableTextHighlight
|
||||
import com.deniscerri.ytdlnis.util.Extensions.setCustomTextSize
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.neo.highlight.core.Highlight
|
||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
class DownloadLogFragment : Fragment() {
|
||||
|
|
@ -105,7 +95,7 @@ class DownloadLogFragment : Fragment() {
|
|||
|
||||
content.isFocusable = true
|
||||
content.enableTextHighlight()
|
||||
|
||||
val slider = view.findViewById<Slider>(R.id.textsize_seekbar)
|
||||
bottomAppBar?.setOnMenuItemClickListener { m: MenuItem ->
|
||||
when(m.itemId){
|
||||
R.id.wrap -> {
|
||||
|
|
@ -140,10 +130,23 @@ class DownloadLogFragment : Fragment() {
|
|||
m.isVisible = false
|
||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||
}
|
||||
|
||||
R.id.text_size -> {
|
||||
slider!!.isVisible = !slider.isVisible
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
slider?.apply {
|
||||
this.valueFrom = 0f
|
||||
this.valueTo = 10f
|
||||
this.value = 2f
|
||||
this.addOnChangeListener { slider, value, fromUser ->
|
||||
content.setCustomTextSize(value + 13f)
|
||||
}
|
||||
}
|
||||
|
||||
contentScrollView.setOnScrollChangeListener { view, sx, sy, osx, osy ->
|
||||
if (sy < osy){
|
||||
bottomAppBar?.menu?.get(1)?.isVisible = contentScrollView.canScrollVertically(1)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.preference.PreferenceManager
|
|||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
|
|
@ -201,7 +202,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
saveFile.writeText(GsonBuilder().setPrettyPrinting().create().toJson(json))
|
||||
val s = Snackbar.make(requireView(), getString(R.string.backup_created_successfully), Snackbar.LENGTH_LONG)
|
||||
s.setAction(R.string.Open_File){
|
||||
UiUtil.openFileIntent(requireContext(), saveFile.absolutePath)
|
||||
UiUtil.openFileIntent(requireActivity(), saveFile.absolutePath)
|
||||
}
|
||||
s.show()
|
||||
}
|
||||
|
|
@ -600,10 +601,11 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
builder.setPositiveButton(
|
||||
getString(R.string.restart)
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
val intent: Intent? = requireContext().packageManager
|
||||
.getLaunchIntentForPackage(requireContext().packageName)
|
||||
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
startActivity(intent!!)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
if(json.has("settings")){
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(preferences.getString("app_language", "en")))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.content.Context.INPUT_METHOD_SERVICE
|
|||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
|
|
@ -23,6 +22,7 @@ import android.widget.TextView
|
|||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
|
@ -38,15 +38,16 @@ import com.deniscerri.ytdlnis.util.FileUtil
|
|||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.Extensions.enableTextHighlight
|
||||
import com.deniscerri.ytdlnis.util.Extensions.setCustomTextSize
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.slider.Slider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
|
|
@ -236,6 +237,8 @@ class TerminalFragment : Fragment() {
|
|||
topAppBar?.menu?.get(0)?.isVisible = false
|
||||
topAppBar?.menu?.get(1)?.isVisible = true
|
||||
topAppBar?.menu?.get(2)?.isVisible = true
|
||||
topAppBar?.menu?.get(3)?.isVisible = true
|
||||
val slider = requireActivity().findViewById<Slider>(R.id.textsize_seekbar)
|
||||
topAppBar?.setOnMenuItemClickListener { m: MenuItem ->
|
||||
when(m.itemId){
|
||||
R.id.wrap -> {
|
||||
|
|
@ -264,9 +267,23 @@ class TerminalFragment : Fragment() {
|
|||
clipboard.setText(output?.text)
|
||||
}
|
||||
}
|
||||
|
||||
R.id.text_size -> {
|
||||
slider?.isVisible = !slider.isVisible
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
slider?.apply {
|
||||
this.valueFrom = 0f
|
||||
this.valueTo = 10f
|
||||
this.value = 2f
|
||||
this.addOnChangeListener { slider, value, fromUser ->
|
||||
output?.setCustomTextSize(value + 13f)
|
||||
input?.setCustomTextSize(value + 13f)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun hideCancelFab() {
|
||||
kotlin.runCatching {
|
||||
|
|
@ -276,7 +293,7 @@ class TerminalFragment : Fragment() {
|
|||
}
|
||||
private fun showCancelFab() {
|
||||
kotlin.runCatching {
|
||||
fab!!.text = getString(R.string.cancel_download)
|
||||
fab!!.text = getString(R.string.cancel_task)
|
||||
fab!!.setIconResource(R.drawable.ic_cancel)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import android.graphics.drawable.shapes.OvalShape
|
|||
import android.media.MediaMetadataRetriever
|
||||
import android.media.MediaMetadataRetriever.METADATA_KEY_DURATION
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -25,6 +27,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.whenStarted
|
||||
import androidx.lifecycle.withStarted
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.neo.highlight.core.Highlight
|
||||
|
|
@ -32,6 +35,7 @@ import com.neo.highlight.util.listener.HighlightTextWatcher
|
|||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import kotlinx.coroutines.launch
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
|
@ -158,4 +162,29 @@ object Extensions {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun JSONObject.getIntByAny(vararg tags:String): Int {
|
||||
tags.forEach {
|
||||
runCatching {
|
||||
return this.getInt(it)
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
fun JSONObject.getStringByAny(vararg tags:String): String {
|
||||
tags.forEach {
|
||||
runCatching {
|
||||
val tmp = this.getString(it)
|
||||
if (tmp != "null") return tmp
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
fun TextView.setCustomTextSize(newSize: Float){
|
||||
this.setTextSize(TypedValue.COMPLEX_UNIT_SP, newSize)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ object FileUtil {
|
|||
MediaScannerConnection.scanFile(context, arrayOf(it), null, null)
|
||||
}
|
||||
}
|
||||
return paths
|
||||
return paths.sortedBy { File(it).lastModified() }
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.Extensions.getIntByAny
|
||||
import com.deniscerri.ytdlnis.util.Extensions.getStringByAny
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
|
|
@ -617,27 +619,13 @@ class InfoUtil(private val context: Context) {
|
|||
for (result in results) {
|
||||
if (result.isNullOrBlank()) continue
|
||||
val jsonObject = JSONObject(result)
|
||||
val title = if (jsonObject.has("title")) {
|
||||
if (jsonObject.getString("title") == "[Private video]") continue
|
||||
jsonObject.getString("title")
|
||||
} else {
|
||||
jsonObject.getString("webpage_url_basename")
|
||||
}
|
||||
var author: String = if (jsonObject.has("uploader")) jsonObject.getString("uploader") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("channel")) jsonObject.getString("channel") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("playlist_uploader")) jsonObject.getString("playlist_uploader") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("uploader_id")) jsonObject.getString("uploader_id") else ""
|
||||
}
|
||||
}
|
||||
}
|
||||
var duration = ""
|
||||
runCatching {
|
||||
if (jsonObject.has("duration")) {
|
||||
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.US)
|
||||
}
|
||||
val title = jsonObject.getStringByAny("track", "alt_title", "title", "webpage_url_basename")
|
||||
if (title == "[Private video]") continue
|
||||
|
||||
val author = jsonObject.getStringByAny("uploader", "channel", "playlist_uploader", "uploader_id")
|
||||
var duration = jsonObject.getIntByAny("duration").toString()
|
||||
if (duration != "-1"){
|
||||
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.US)
|
||||
}
|
||||
|
||||
var thumb: String? = ""
|
||||
|
|
@ -649,16 +637,15 @@ class InfoUtil(private val context: Context) {
|
|||
thumb = thumbs.getJSONObject(thumbs.length() - 1).getString("url")
|
||||
}
|
||||
}
|
||||
val website = jsonObject.getString(listOf("ie_key", "extractor_key", "extractor").first { jsonObject.has(it) })
|
||||
|
||||
var playlistTitle: String? = ""
|
||||
val website = jsonObject.getStringByAny("ie_key", "extractor_key", "extractor")
|
||||
var playlistTitle = jsonObject.getStringByAny("playlist_title")
|
||||
var playlistURL: String? = ""
|
||||
var playlistIndex: Int? = null
|
||||
|
||||
if (jsonObject.has("playlist_title")) playlistTitle = jsonObject.getString("playlist_title")
|
||||
if(playlistTitle?.removeSurrounding("\"").equals(query)) playlistTitle = ""
|
||||
if(playlistTitle.removeSurrounding("\"") == query) playlistTitle = ""
|
||||
|
||||
if (playlistTitle?.isNotBlank() == true){
|
||||
if (playlistTitle.isNotBlank()){
|
||||
playlistURL = query
|
||||
kotlin.runCatching { playlistIndex = jsonObject.getInt("playlist_index") }
|
||||
}
|
||||
|
|
@ -703,7 +690,7 @@ class InfoUtil(private val context: Context) {
|
|||
duration,
|
||||
thumb!!,
|
||||
website,
|
||||
playlistTitle!!,
|
||||
playlistTitle,
|
||||
formats,
|
||||
urls,
|
||||
chapters,
|
||||
|
|
@ -788,22 +775,12 @@ class InfoUtil(private val context: Context) {
|
|||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val jsonObject = JSONObject(youtubeDLResponse.out)
|
||||
|
||||
var author: String = if (jsonObject.has("uploader")) jsonObject.getString("uploader") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("channel")) jsonObject.getString("channel") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("playlist_uploader")) jsonObject.getString("playlist_uploader") else ""
|
||||
if (author.isEmpty() || author == "null"){
|
||||
author = if (jsonObject.has("uploader_id")) jsonObject.getString("uploader_id") else ""
|
||||
}
|
||||
}
|
||||
}
|
||||
val title = jsonObject.getStringByAny("track", "alt_title", "title", "webpage_url_basename")
|
||||
val author = jsonObject.getStringByAny("uploader", "channel", "playlist_uploader", "uploader_id")
|
||||
|
||||
var duration = ""
|
||||
runCatching {
|
||||
if (jsonObject.has("duration")) {
|
||||
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.US)
|
||||
}
|
||||
var duration = jsonObject.getIntByAny("duration").toString()
|
||||
if (duration != "-1"){
|
||||
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.US)
|
||||
}
|
||||
|
||||
var thumb: String? = ""
|
||||
|
|
@ -820,11 +797,7 @@ class InfoUtil(private val context: Context) {
|
|||
return ResultItem(
|
||||
0,
|
||||
url,
|
||||
if (isPlaylist){
|
||||
""
|
||||
}else{
|
||||
jsonObject.getString("title")
|
||||
},
|
||||
if (isPlaylist) "" else title,
|
||||
author,
|
||||
duration,
|
||||
thumb!!,
|
||||
|
|
@ -986,8 +959,7 @@ class InfoUtil(private val context: Context) {
|
|||
YoutubeDLRequest(downloadItem.url)
|
||||
}else{
|
||||
YoutubeDLRequest(downloadItem.playlistURL!!).apply {
|
||||
addOption("--playlist-start", downloadItem.playlistIndex!!)
|
||||
addOption("--playlist-end", downloadItem.playlistIndex!!)
|
||||
addOption("-I", "${downloadItem.playlistIndex!!}:${downloadItem.playlistIndex}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1117,7 +1089,7 @@ class InfoUtil(private val context: Context) {
|
|||
"%(section_title&{} |)s$filenameTemplate"
|
||||
}
|
||||
if (downloadItem.downloadSections.split(";").size > 1){
|
||||
filenameTemplate = "%(autonumber)d. %(section_start>%H:%M:%S)s $filenameTemplate"
|
||||
filenameTemplate = "%(autonumber)d. %(section_start>%H∶%M∶%S)s $filenameTemplate"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1145,11 +1117,11 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
if (downloadItem.playlistTitle.isNotBlank()){
|
||||
request.addOption("--parse-metadata","${downloadItem.playlistTitle}:%(playlist)s")
|
||||
request.addCommands(listOf("--replace-in-metadata", "playlist", ".+", downloadItem.playlistTitle))
|
||||
runCatching {
|
||||
request.addOption("--parse-metadata",
|
||||
downloadItem.playlistIndex.toString() + ":%(playlist_index)s"
|
||||
)
|
||||
if (downloadItem.playlistIndex != null){
|
||||
request.addOption("--parse-metadata", downloadItem.playlistIndex.toString() + ":%(playlist_index)s")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1209,6 +1181,7 @@ class InfoUtil(private val context: Context) {
|
|||
request.addOption("--embed-metadata")
|
||||
|
||||
request.addOption("--parse-metadata", "%(release_year,release_date>%Y,upload_date>%Y)s:%(meta_date)s")
|
||||
request.addOption("--parse-metadata", "video:%(uploader)s:%(album_artist)s")
|
||||
|
||||
if (downloadItem.playlistTitle.isNotEmpty()) {
|
||||
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
||||
|
|
@ -1279,6 +1252,10 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
val f = StringBuilder()
|
||||
|
||||
val preferredCodec = sharedPreferences.getString("video_codec", "")
|
||||
val vCodecPrefIndex = context.getStringArray(R.array.video_codec_values).indexOf(preferredCodec)
|
||||
val vCodecPref = context.getStringArray(R.array.video_codec_values_ytdlp)[vCodecPrefIndex]
|
||||
|
||||
val defaultFormats = context.resources.getStringArray(R.array.video_formats_values)
|
||||
val usingGenericFormat = defaultFormats.contains(videoF) || downloadItem.allFormats.isEmpty() || downloadItem.allFormats == getGenericVideoFormats(context.resources)
|
||||
if (!usingGenericFormat){
|
||||
|
|
@ -1333,9 +1310,7 @@ class InfoUtil(private val context: Context) {
|
|||
request.addOption("--audio-multistreams")
|
||||
}
|
||||
|
||||
val preferredCodec = sharedPreferences.getString("video_codec", "")
|
||||
val vCodecPrefIndex = context.getStringArray(R.array.video_codec_values).indexOf(preferredCodec)
|
||||
val vCodecPref = context.getStringArray(R.array.video_codec_values_ytdlp)[vCodecPrefIndex]
|
||||
|
||||
preferredFormatIDs.forEach { v ->
|
||||
preferredAudioFormatIDs.forEach { a ->
|
||||
val aa = if (a.isNotBlank()) "+$a" else ""
|
||||
|
|
@ -1345,13 +1320,21 @@ class InfoUtil(private val context: Context) {
|
|||
if (!downloadItem.videoPreferences.removeAudio){
|
||||
//build format with audio with preferred language
|
||||
if (preferredAudioLanguage.isNotBlank()){
|
||||
val al = "$v+ba[language^=$preferredAudioLanguage]/"
|
||||
val al = if (v == "wv"){
|
||||
"$v+wa[language^=$preferredAudioLanguage]/"
|
||||
}else{
|
||||
"$v+ba[language^=$preferredAudioLanguage]/"
|
||||
}
|
||||
if (!f.contains(al)) f.append(al)
|
||||
}
|
||||
//build format with best audio
|
||||
if (!f.contains("$v+ba/") && !f.contains("wa")) f.append("$v+ba/")
|
||||
//build format with standalone video
|
||||
f.append("$v/")
|
||||
if (v == "wv"){
|
||||
f.append("w/")
|
||||
}else{
|
||||
if (v != "bv") f.append("$v/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1360,15 +1343,15 @@ class InfoUtil(private val context: Context) {
|
|||
f.append("b")
|
||||
}
|
||||
|
||||
StringBuilder().apply {
|
||||
if (vCodecPref.isNotBlank()) append(",vcodec:$vCodecPref")
|
||||
if (aCodecPref.isNotBlank()) append(",acodec:$aCodecPref")
|
||||
if (cont.isNotBlank()) append(",ext:$cont")
|
||||
if (this.isNotBlank()){
|
||||
request.addOption("-S", "+hasaud$this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder().apply {
|
||||
if (vCodecPref.isNotBlank()) append(",vcodec:$vCodecPref")
|
||||
if (aCodecPref.isNotBlank()) append(",acodec:$aCodecPref")
|
||||
if (cont.isNotBlank()) append(",ext:$cont")
|
||||
if (this.isNotBlank()){
|
||||
request.addOption("-S", "+hasaud$this")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ class NotificationUtil(var context: Context) {
|
|||
}
|
||||
|
||||
fun showQueriesFinished() {
|
||||
val notificationBuilder = getBuilder(DOWNLOAD_FINISHED_CHANNEL_ID)
|
||||
val notificationBuilder = getBuilder(DOWNLOAD_MISC_CHANNEL_ID)
|
||||
|
||||
val openMultipleDownloads = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import android.util.Log
|
|||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.Window
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Button
|
||||
|
|
@ -26,17 +27,15 @@ import android.widget.EditText
|
|||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.ui.text.font.Typeface
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.text.toUpperCase
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.fragment.app.FragmentManager
|
||||
|
|
@ -57,6 +56,9 @@ import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
|||
import com.deniscerri.ytdlnis.ui.downloadcard.ConfigureDownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.VideoCutListener
|
||||
import com.deniscerri.ytdlnis.util.Extensions.enableTextHighlight
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.badge.BadgeUtils
|
||||
import com.google.android.material.badge.ExperimentalBadgeUtils
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
|
@ -81,6 +83,7 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
|
|
@ -380,6 +383,46 @@ object UiUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private fun openMultipleFilesIntent(context: Activity, path: List<String>){
|
||||
val bottomSheet = BottomSheetDialog(context)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.filepathlist)
|
||||
|
||||
val list = bottomSheet.findViewById<LinearLayout>(R.id.filepath_list)
|
||||
|
||||
list?.apply {
|
||||
path.forEach {path ->
|
||||
val file = File(path)
|
||||
val item = context.layoutInflater.inflate(R.layout.filepath_card, list, false)
|
||||
item.apply {
|
||||
findViewById<TextView>(R.id.file_name).text = file.nameWithoutExtension
|
||||
findViewById<TextView>(R.id.filesize).text = FileUtil.convertFileSize(file.length())
|
||||
findViewById<TextView>(R.id.extension).text = file.extension.uppercase()
|
||||
if (!file.exists()){
|
||||
isEnabled = false
|
||||
alpha = 0.7f
|
||||
}
|
||||
isEnabled = file.exists()
|
||||
setOnClickListener {
|
||||
openFileIntent(context, path)
|
||||
bottomSheet.dismiss()
|
||||
}
|
||||
}
|
||||
list.addView(item)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
val displayMetrics = DisplayMetrics()
|
||||
context.windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
fun shareFileIntent(context: Context, paths: List<String>){
|
||||
val uris : ArrayList<Uri> = arrayListOf()
|
||||
paths.runCatching {
|
||||
|
|
@ -479,14 +522,16 @@ object UiUtil {
|
|||
bottomSheet.setContentView(R.layout.history_item_details_bottom_sheet)
|
||||
bottomSheet.findViewById<TextView>(R.id.bottom_sheet_title)?.apply {
|
||||
text = item.title.ifEmpty { "`${context.getString(R.string.defaultValue)}`" }
|
||||
setOnClickListener{
|
||||
setOnLongClickListener{
|
||||
showFullTextDialog(context, text.toString(), context.getString(R.string.title))
|
||||
true
|
||||
}
|
||||
}
|
||||
bottomSheet.findViewById<TextView>(R.id.bottom_sheet_author)?.apply {
|
||||
text = item.author.ifEmpty { "`${context.getString(R.string.defaultValue)}`" }
|
||||
setOnClickListener{
|
||||
setOnLongClickListener{
|
||||
showFullTextDialog(context, text.toString(), context.getString(R.string.author))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,8 +727,25 @@ object UiUtil {
|
|||
btn?.setImageResource(typeImageResource)
|
||||
|
||||
if (isPresent){
|
||||
btn?.setOnClickListener {
|
||||
shareFileIntent(context, listOf(item.downloadPath))
|
||||
btn?.apply {
|
||||
if (item.downloadPath.size > 1){
|
||||
viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
@OptIn(ExperimentalBadgeUtils::class) override fun onGlobalLayout() {
|
||||
val badgeDrawable = BadgeDrawable.create(context)
|
||||
badgeDrawable.number = item.downloadPath.size
|
||||
//Important to change the position of the Badge
|
||||
badgeDrawable.horizontalOffset = 25
|
||||
badgeDrawable.verticalOffset = 25
|
||||
BadgeUtils.attachBadgeDrawable(badgeDrawable, btn, null)
|
||||
btn.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setOnClickListener {
|
||||
shareFileIntent(context, item.downloadPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -693,7 +755,7 @@ object UiUtil {
|
|||
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
|
||||
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
|
||||
val command = bottomSheet.findViewById<Chip>(R.id.command)
|
||||
val file = File(item.downloadPath)
|
||||
val file = File(item.downloadPath.first())
|
||||
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = item.time * 1000L
|
||||
|
|
@ -708,7 +770,7 @@ object UiUtil {
|
|||
formatNote?.isVisible = false
|
||||
}
|
||||
|
||||
if (item.format.container != "") {
|
||||
if (item.format.container != "" && item.downloadPath.size == 1) {
|
||||
container!!.text = if (file.exists()) file.extension.uppercase() else item.format.container.uppercase()
|
||||
container.setChipIconResource(typeImageResource)
|
||||
}else {
|
||||
|
|
@ -723,7 +785,7 @@ object UiUtil {
|
|||
} else {
|
||||
item.format.acodec.uppercase()
|
||||
}
|
||||
if (codecText == "" || codecText == "none"){
|
||||
if (codecText == "" || codecText == "none" || item.downloadPath.size > 1){
|
||||
codec!!.visibility = View.GONE
|
||||
}else{
|
||||
codec!!.visibility = View.VISIBLE
|
||||
|
|
@ -731,7 +793,7 @@ object UiUtil {
|
|||
}
|
||||
|
||||
val fileSizeReadable = FileUtil.convertFileSize(if (file.exists()) file.length() else item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
if (fileSizeReadable == "?" || item.downloadPath.size > 1) fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
command?.setOnClickListener {
|
||||
|
|
@ -761,7 +823,11 @@ object UiUtil {
|
|||
val openFile = bottomSheet.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
||||
openFile!!.tag = item.id
|
||||
openFile.setOnClickListener{
|
||||
openFileIntent(context, item.downloadPath)
|
||||
if (item.downloadPath.size == 1) {
|
||||
openFileIntent(context, item.downloadPath.first())
|
||||
}else{
|
||||
openMultipleFilesIntent(context, item.downloadPath)
|
||||
}
|
||||
}
|
||||
|
||||
val redownload = bottomSheet.findViewById<Button>(R.id.bottomsheet_redownload_button)
|
||||
|
|
@ -1044,11 +1110,8 @@ object UiUtil {
|
|||
val chip = activity.layoutInflater.inflate(R.layout.suggestion_chip, chipGroup, false) as Chip
|
||||
chip.text = shortcut.content
|
||||
chip.setOnClickListener {
|
||||
if (chip.isChecked){
|
||||
itemSelected(shortcut.content)
|
||||
}else{
|
||||
itemRemoved(shortcut.content)
|
||||
}
|
||||
chip.isChecked = false
|
||||
itemSelected(shortcut.content)
|
||||
}
|
||||
chipGroup.addView(chip)
|
||||
}
|
||||
|
|
@ -1081,6 +1144,8 @@ object UiUtil {
|
|||
extraCommandsClicked: () -> Unit,
|
||||
updateDataClicked: () -> Unit
|
||||
){
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
|
||||
val saveSubtitles = view.findViewById<Chip>(R.id.save_subtitles)
|
||||
val subtitleLanguages = view.findViewById<Chip>(R.id.subtitle_languages)
|
||||
|
|
@ -1127,6 +1192,7 @@ object UiUtil {
|
|||
}
|
||||
|
||||
val sponsorBlock = view.findViewById<Chip>(R.id.sponsorblock_filters)
|
||||
sponsorBlock.isEnabled = sharedPreferences.getBoolean("use_sponsorblock", true)
|
||||
sponsorBlock!!.setOnClickListener {
|
||||
val builder = MaterialAlertDialogBuilder(context)
|
||||
builder.setTitle(context.getString(R.string.select_sponsorblock_filtering))
|
||||
|
|
@ -1228,7 +1294,6 @@ object UiUtil {
|
|||
}
|
||||
|
||||
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
items.forEach { it.videoPreferences.subsLanguages = sharedPreferences.getString("subs_lang", "en.*,.*-orig")!! }
|
||||
if (items.all { it.videoPreferences.writeSubs}) {
|
||||
|
|
@ -1638,8 +1703,7 @@ object UiUtil {
|
|||
val deleteDialog = MaterialAlertDialogBuilder(context)
|
||||
deleteDialog.setTitle(context.getString(R.string.you_are_going_to_delete) + " \"" + item.title + "\"!")
|
||||
val path = item.downloadPath
|
||||
val file = File(path)
|
||||
if (file.exists() && path.isNotEmpty()) {
|
||||
if (path.any { File(it).exists() && it.isNotEmpty() }) {
|
||||
deleteDialog.setMultiChoiceItems(
|
||||
arrayOf(context.getString(R.string.delete_file_too)),
|
||||
booleanArrayOf(false)
|
||||
|
|
@ -1839,14 +1903,14 @@ object UiUtil {
|
|||
|
||||
builder.setView(view)
|
||||
builder.setPositiveButton(
|
||||
context.getString(android.R.string.copy)
|
||||
context.getString(R.string.dismiss)
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
copyToClipboard(txt, context)
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
context.getString(R.string.cancel)
|
||||
context.getString(android.R.string.cancel)
|
||||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.work
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
|
|
@ -46,6 +47,7 @@ class DownloadWorker(
|
|||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
@SuppressLint("RestrictedApi")
|
||||
override suspend fun doWork(): Result {
|
||||
if (isStopped) return Result.success()
|
||||
|
||||
|
|
@ -126,7 +128,7 @@ class DownloadWorker(
|
|||
val logString = StringBuilder("\n ${commandString}\n\n")
|
||||
val logItem = LogItem(
|
||||
0,
|
||||
downloadItem.title.ifEmpty { downloadItem.url },
|
||||
downloadItem.title.ifBlank { downloadItem.url },
|
||||
"Downloading:\n" +
|
||||
"Title: ${downloadItem.title}\n" +
|
||||
"URL: ${downloadItem.url}\n" +
|
||||
|
|
@ -168,10 +170,12 @@ class DownloadWorker(
|
|||
if (noCache){
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Scanning Files", "id" to downloadItem.id))
|
||||
finalPaths = it.out.split("\n")
|
||||
.asSequence()
|
||||
.filter { it.startsWith("'/storage") }
|
||||
.map { it.removePrefix("'") }
|
||||
.map { it.removeSuffix("\n") }
|
||||
.map { it.removeSuffix("'") }
|
||||
.sortedBy { File(it).lastModified() }
|
||||
.toList()
|
||||
// finalPaths = File(FileUtil.formatPath(downloadLocation))
|
||||
// .walkTopDown()
|
||||
|
|
@ -191,7 +195,7 @@ class DownloadWorker(
|
|||
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))
|
||||
}
|
||||
}
|
||||
}.filter { !it.matches("\\.(description)|(txt)\$".toRegex()) }
|
||||
|
||||
if (finalPaths.isNotEmpty()){
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id))
|
||||
|
|
@ -207,6 +211,7 @@ class DownloadWorker(
|
|||
}
|
||||
}
|
||||
|
||||
finalPaths = finalPaths?.filter { !it.matches("(\\.description)|(\\.srt)|(\\.ass)|(\\.lrc)|(\\.vtt)|(\\.txt)|(\\.jpg)|(\\.png)\$".toRegex()) }
|
||||
FileUtil.deleteConfigFiles(request)
|
||||
|
||||
//put download in history
|
||||
|
|
@ -218,29 +223,27 @@ class DownloadWorker(
|
|||
}
|
||||
}else{
|
||||
val unixTime = System.currentTimeMillis() / 1000
|
||||
finalPaths?.forEachIndexed {idx, ff ->
|
||||
val file = File(ff)
|
||||
var index = ""
|
||||
var duration = downloadItem.duration
|
||||
if (idx > 0) {
|
||||
index = "[${idx + 1}] "
|
||||
downloadItem.author = file.nameWithoutExtension
|
||||
}
|
||||
val d = file.getMediaDuration(context)
|
||||
if (d > 0) duration = infoUtil.formatIntegerDuration(d, Locale.US)
|
||||
finalPaths?.apply {
|
||||
this.first().apply {
|
||||
val file = File(this)
|
||||
var duration = downloadItem.duration
|
||||
val d = file.getMediaDuration(context)
|
||||
if (d > 0) duration = infoUtil.formatIntegerDuration(d, Locale.US)
|
||||
|
||||
downloadItem.format.filesize = file.length()
|
||||
downloadItem.format.container = file.extension
|
||||
downloadItem.duration = duration
|
||||
}
|
||||
|
||||
downloadItem.format.filesize = file.length()
|
||||
downloadItem.format.container = file.extension
|
||||
downloadItem.duration = duration
|
||||
val historyItem = HistoryItem(0,
|
||||
downloadItem.url,
|
||||
index + downloadItem.title,
|
||||
downloadItem.title,
|
||||
downloadItem.author,
|
||||
downloadItem.duration,
|
||||
downloadItem.thumb,
|
||||
downloadItem.type,
|
||||
unixTime,
|
||||
ff,
|
||||
this,
|
||||
downloadItem.website,
|
||||
downloadItem.format,
|
||||
downloadItem.id,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" 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="M4,22H2V2h2V22zM22,7H6v3h16V7zM16,14H6v3h10V14z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/baseline_expand_less_24.xml
Normal file
5
app/src/main/res/drawable/baseline_expand_less_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="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/baseline_expand_more_24.xml
Normal file
5
app/src/main/res/drawable/baseline_expand_more_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="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
|
||||
</vector>
|
||||
|
|
@ -17,106 +17,65 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_history_scroll_view"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
app:singleLine="false" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
app:singleSelection="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-10dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/link_you_copied"
|
||||
layout="@layout/search_suggestion_item"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_suggestions_scroll_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/search_suggestions_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -269,31 +228,37 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_all_coordinator"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|end">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/copied_url_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:contentDescription="@string/link_you_copied"
|
||||
android:src="@drawable/ic_clipboard"
|
||||
android:text="@string/download_all"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_all_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:text="@string/download_all"
|
||||
app:icon="@drawable/ic_down"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
app:icon="@drawable/ic_down" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_selected_fab"
|
||||
android:visibility="gone"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -303,9 +268,7 @@
|
|||
android:text="@string/download"
|
||||
app:srcCompat="@drawable/ic_music"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,186 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/player_constraint"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_default="percent"
|
||||
app:layout_constraintWidth_percent=".67">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/frame_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:layout_constraintDimensionRatio="H,16:9"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
|
||||
<androidx.media3.ui.PlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:resize_mode="fixed_height"
|
||||
app:useDefaultControls="true"
|
||||
app:use_controller="true" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_thumb"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:colorAccent"
|
||||
app:layout_constraintTop_toTopOf="@+id/frame_layout"
|
||||
app:layout_constraintEnd_toEndOf="@+id/frame_layout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.277"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frame_layout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||
app:layout_constraintTop_toBottomOf="@id/frame_layout" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintEnd_toEndOf="@id/frame_layout"
|
||||
app:layout_constraintTop_toBottomOf="@id/frame_layout" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottom_sheet_link"
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_link"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_music"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/info"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/player_constraint"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/running"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:text="@string/running"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/running_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/queued"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:text="@string/download_queue"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/queued_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -17,106 +17,65 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_history_scroll_view"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
app:singleLine="false" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="20dp"
|
||||
app:singleSelection="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-10dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/link_you_copied"
|
||||
layout="@layout/search_suggestion_item"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_suggestions_scroll_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/search_suggestions_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -275,37 +234,42 @@
|
|||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/home_fabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_all_coordinator"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|end">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/copied_url_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:contentDescription="@string/link_you_copied"
|
||||
android:src="@drawable/ic_clipboard"
|
||||
android:text="@string/download_all"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_all_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:text="@string/download_all"
|
||||
app:icon="@drawable/ic_down"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
app:icon="@drawable/ic_down" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_selected_fab"
|
||||
android:visibility="gone"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -315,9 +279,7 @@
|
|||
android:text="@string/download"
|
||||
app:srcCompat="@drawable/ic_music"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,106 +17,65 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_history_scroll_view"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
app:singleLine="false" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
app:singleSelection="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-10dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/link_you_copied"
|
||||
layout="@layout/search_suggestion_item"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_suggestions_scroll_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/search_suggestions_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -269,31 +228,37 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_all_coordinator"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|end">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/copied_url_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:contentDescription="@string/link_you_copied"
|
||||
android:src="@drawable/ic_clipboard"
|
||||
android:text="@string/download_all"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_all_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:text="@string/download_all"
|
||||
app:icon="@drawable/ic_down"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
app:icon="@drawable/ic_down" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_selected_fab"
|
||||
android:visibility="gone"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -303,9 +268,7 @@
|
|||
android:text="@string/download"
|
||||
app:srcCompat="@drawable/ic_music"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,106 +17,65 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_history_scroll_view"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
app:singleLine="false" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-10dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/link_you_copied"
|
||||
layout="@layout/search_suggestion_item"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_suggestions_scroll_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/search_suggestions_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -294,37 +253,42 @@
|
|||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/home_fabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_all_coordinator"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|end">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/copied_url_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:contentDescription="@string/link_you_copied"
|
||||
android:src="@drawable/ic_clipboard"
|
||||
android:text="@string/download_all"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_all_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:text="@string/download_all"
|
||||
app:icon="@drawable/ic_down"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
app:icon="@drawable/ic_down" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_selected_fab"
|
||||
android:visibility="gone"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -334,10 +298,9 @@
|
|||
android:text="@string/download"
|
||||
app:srcCompat="@drawable/ic_music"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -28,6 +28,18 @@
|
|||
app:title="@string/terminal" />
|
||||
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:visibility="gone"
|
||||
android:id="@+id/textsize_seekbar"
|
||||
android:padding="0dp"
|
||||
android:layout_margin="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@
|
|||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="20dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
@ -37,7 +38,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_loading_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
|
|
@ -64,9 +65,10 @@
|
|||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:layout_marginEnd="20dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/shimmer_loading_title"
|
||||
|
|
@ -74,7 +76,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
|
|
|
|||
|
|
@ -1,61 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/filename"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/filename_edittext"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/filename"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/filename_edittext"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/suggested"
|
||||
android:layout_width="0dp"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/filename"
|
||||
android:text="@string/suggested" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHeight_max="200dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/suggested">
|
||||
<TextView
|
||||
android:id="@+id/suggested"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/filename"
|
||||
android:text="@string/suggested" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/filename_suggested_chipgroup"
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:chipSpacingVertical="-7dp"
|
||||
app:chipSpacingHorizontal="5dp"
|
||||
app:selectionRequired="false"
|
||||
app:singleSelection="false">
|
||||
app:layout_constraintHeight_max="200dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/suggested">
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/filename_suggested_chipgroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:chipSpacingVertical="-7dp"
|
||||
app:chipSpacingHorizontal="5dp"
|
||||
app:selectionRequired="false"
|
||||
app:singleSelection="false">
|
||||
|
||||
</ScrollView>
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
|||
109
app/src/main/res/layout/filepath_card.xml
Normal file
109
app/src/main/res/layout/filepath_card.xml
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="10dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/download_item_data"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="0.7"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/file_name"
|
||||
app:layout_constraintVertical_bias="0.0">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesize"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/rounded_corner"
|
||||
android:backgroundTint="?attr/colorSecondary"
|
||||
android:clickable="false"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLength="17"
|
||||
android:maxLines="1"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/extension"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/rounded_corner"
|
||||
android:backgroundTint="?attr/colorSecondary"
|
||||
android:clickable="false"
|
||||
android:gravity="center"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/action_button"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp"
|
||||
android:padding="0dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:iconTint="?attr/colorAccent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
67
app/src/main/res/layout/filepathlist.xml
Normal file
67
app/src/main/res/layout/filepathlist.xml
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/Open_File"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/select"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:padding="5dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/filepath_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
76
app/src/main/res/layout/format_category_sheet.xml
Normal file
76
app/src/main/res/layout/format_category_sheet.xml
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout style="@style/Widget.Material3.BottomSheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/all"
|
||||
android:layout_marginTop="20dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingVertical="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp"
|
||||
android:text="@string/all"
|
||||
app:drawableStartCompat="@drawable/ic_check" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/suggested"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingVertical="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp"
|
||||
android:text="@string/suggested"
|
||||
app:drawableStartCompat="@drawable/empty" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/smallest"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingVertical="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp"
|
||||
android:text="@string/format_smallest"
|
||||
app:drawableStartCompat="@drawable/empty" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/generic"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingVertical="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp"
|
||||
android:text="@string/generic"
|
||||
app:drawableStartCompat="@drawable/empty" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -23,49 +23,80 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/format"
|
||||
android:layout_marginTop="4dp"
|
||||
android:maxLines="2"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:singleLine="false"
|
||||
android:text="@string/format"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_buttons"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:singleLine="false"
|
||||
android:text="@string/select_format"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_buttons"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/format_ok"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
<LinearLayout
|
||||
android:id="@+id/format_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/format_filter"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:icon="@drawable/baseline_align_horizontal_left_24"
|
||||
app:layout_constraintBottom_toBottomOf="@id/format_refresh"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_refresh"
|
||||
app:layout_constraintTop_toTopOf="@id/format_refresh" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/format_refresh"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/update_formats"
|
||||
app:icon="@drawable/ic_refresh"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/format_ok"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/format_refresh"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/update_formats"
|
||||
app:icon="@drawable/ic_refresh"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@
|
|||
app:navigationIcon="@drawable/ic_back"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:visibility="gone"
|
||||
android:id="@+id/textsize_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,106 +17,65 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_history_scroll_view"
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
app:singleLine="false" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/providers"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_width="wrap_content"
|
||||
app:singleSelection="true"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/chipGroupDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
style="@style/Divider.Vertical"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/queries_constraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/queries"
|
||||
android:layout_margin="10dp"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/init_search_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/init_search_query"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:iconSize="20dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-10dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/link_you_copied"
|
||||
layout="@layout/search_suggestion_item"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_history_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/search_suggestions_scroll_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/search_suggestions_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -198,43 +157,49 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_all_coordinator"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|end">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/copied_url_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:contentDescription="@string/link_you_copied"
|
||||
android:src="@drawable/ic_clipboard"
|
||||
android:text="@string/download_all"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_all_fab"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/download_all"
|
||||
app:icon="@drawable/ic_down"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/download_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
app:icon="@drawable/ic_down" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/download_selected_fab"
|
||||
android:visibility="gone"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:icon="@drawable/ic_down"
|
||||
android:text="@string/download"
|
||||
app:srcCompat="@drawable/ic_music"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@
|
|||
|
||||
</ScrollView>
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -65,6 +64,9 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
|
||||
|
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar
|
||||
android:id="@+id/bottomAppBar"
|
||||
style="@style/Widget.Material3.BottomAppBar"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="H,2.66:1"
|
||||
app:layout_constraintDimensionRatio="H,2.5:1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
|
@ -136,8 +136,8 @@
|
|||
android:clickable="false"
|
||||
app:cornerRadius="10dp"
|
||||
android:elevation="0dp"
|
||||
app:borderWidth="0dp"
|
||||
app:elevation="0dp"
|
||||
app:borderWidth="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
|
|||
174
app/src/main/res/layout/history_card_multiple.xml
Normal file
174
app/src/main/res/layout/history_card_multiple.xml
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="H,2.5:1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/downloads_card_view2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginHorizontal="35dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:checkable="false"
|
||||
app:cardCornerRadius="15dp"
|
||||
app:cardElevation="5dp"
|
||||
app:cardMaxElevation="12dp"
|
||||
app:cardPreventCornerOverlap="true"
|
||||
app:checkedIcon="@null"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:strokeWidth="0dp" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/downloads_card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardElevation="5dp"
|
||||
app:checkedIcon="@null"
|
||||
app:cardMaxElevation="12dp"
|
||||
android:checkable="true"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginVertical="15dp"
|
||||
app:strokeWidth="0dp"
|
||||
app:cardPreventCornerOverlap="true">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/downloads_image_view"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:dividerPadding="5dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/downloads_info_time"
|
||||
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/downloads_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="2"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/downloads_info_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="1.5"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/length"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="1"
|
||||
android:padding="10dp"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="10"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/downloads_info_time"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/downloads_info_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="1"
|
||||
android:scrollbars="none"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="10"
|
||||
android:textColor="#FFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/downloads_download_button_type"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/downloads_download_button_type"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:clickable="false"
|
||||
app:cornerRadius="10dp"
|
||||
android:elevation="0dp"
|
||||
app:elevation="0dp"
|
||||
app:borderWidth="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -1,200 +1,207 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingBottom="20dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/frame_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:layout_constraintDimensionRatio="H,16:9"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
|
||||
<androidx.media3.ui.PlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:resize_mode="fixed_height"
|
||||
app:useDefaultControls="true"
|
||||
app:use_controller="true" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_thumb"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:colorAccent"
|
||||
app:layout_constraintTop_toTopOf="@+id/frame_layout"
|
||||
app:layout_constraintEnd_toEndOf="@+id/frame_layout" />
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:orientation="vertical"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frame_layout"
|
||||
android:paddingBottom="20dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/frame_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:layout_constraintDimensionRatio="H,16:9"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/list_section"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
<androidx.media3.ui.PlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:resize_mode="fixed_height"
|
||||
app:useDefaultControls="true"
|
||||
app:use_controller="true" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_thumb"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:iconSize="30dp"
|
||||
app:iconTint="?android:colorAccent"
|
||||
app:layout_constraintTop_toTopOf="@+id/frame_layout"
|
||||
app:layout_constraintEnd_toEndOf="@+id/frame_layout" />
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp">
|
||||
android:layout_width="match_parent"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frame_layout"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/list_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/nestedScrollView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
android:singleLine="false"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/nestedScrollView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_music"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_music"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_music"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/download_video"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
app:icon="@drawable/ic_video"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/title_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="bottom_info,download_music" />
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/title_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="bottom_info,download_music" />
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/nestedScrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title_barrier">
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/nestedScrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title_barrier">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/running"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:text="@string/running"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/running_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/running" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/queued"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:text="@string/download_queue"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/running_recycler" />
|
||||
<TextView
|
||||
android:id="@+id/running"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:text="@string/running"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/running_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/running" />
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/queued_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queued" />
|
||||
<TextView
|
||||
android:id="@+id/queued"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:text="@string/download_queue"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/running_recycler" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottom_sheet_link"
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_link"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queued_recycler" />
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/queued_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queued" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<Button
|
||||
android:id="@+id/bottom_sheet_link"
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_link"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queued_recycler" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linear"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="5dp"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -1,61 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/subtitle"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/subtitle_edittext"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/subtitle"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/subtitle_edittext"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/suggested"
|
||||
android:layout_width="0dp"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/subtitle"
|
||||
android:text="@string/suggested" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHeight_max="200dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/suggested">
|
||||
<TextView
|
||||
android:id="@+id/suggested"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/subtitle"
|
||||
android:text="@string/suggested" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/subtitle_suggested_chipgroup"
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:chipSpacingVertical="-7dp"
|
||||
app:chipSpacingHorizontal="5dp"
|
||||
app:selectionRequired="false"
|
||||
app:singleSelection="false">
|
||||
app:layout_constraintHeight_max="200dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/suggested">
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/subtitle_suggested_chipgroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:chipSpacingVertical="-7dp"
|
||||
app:chipSpacingHorizontal="5dp"
|
||||
app:selectionRequired="false"
|
||||
app:singleSelection="false">
|
||||
|
||||
</ScrollView>
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
@ -14,7 +14,13 @@
|
|||
android:title=""
|
||||
android:visible="false"
|
||||
android:icon="@drawable/ic_down"
|
||||
app:showAsAction="ifRoom" />
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/text_size"
|
||||
android:title=""
|
||||
android:icon="@drawable/ic_textformat"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
app:showAsAction="always"
|
||||
android:id="@+id/wrap"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/text_size"
|
||||
android:title=""
|
||||
android:icon="@drawable/ic_textformat"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/export_clipboard"
|
||||
android:title="@string/export_from_clipboard"
|
||||
|
|
|
|||
|
|
@ -155,9 +155,17 @@
|
|||
<dialog
|
||||
android:id="@+id/downloadBottomSheetDialog"
|
||||
android:name="com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog"
|
||||
android:label="DownloadBottomSheetDialog" />
|
||||
android:label="DownloadBottomSheetDialog" >
|
||||
<action
|
||||
android:id="@+id/action_downloadBottomSheetDialog_to_cutVideoBottomSheetDialog"
|
||||
app:destination="@id/cutVideoBottomSheetDialog" />
|
||||
</dialog>
|
||||
<dialog
|
||||
android:id="@+id/downloadMultipleBottomSheetDialog2"
|
||||
android:name="com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog"
|
||||
android:label="DownloadMultipleBottomSheetDialog" />
|
||||
<dialog
|
||||
android:id="@+id/cutVideoBottomSheetDialog"
|
||||
android:name="com.deniscerri.ytdlnis.ui.downloadcard.CutVideoBottomSheetDialog"
|
||||
android:label="CutVideoBottomSheetDialog" />
|
||||
</navigation>
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
<string name="video_format">صيغة الفيديو</string>
|
||||
<string name="audio_quality">جودة الصوت</string>
|
||||
<string name="audio_quality_summary">0(الأفضل) 10(الأدنى)</string>
|
||||
<string name="cancel_download">إلغاء التحميل</string>
|
||||
<string name="cancel_task">إلغاء التحميل</string>
|
||||
<string name="run_command">تشغيل الأمر</string>
|
||||
<string name="command_download_notification_channel_name">تحميلات الأوامر</string>
|
||||
<string name="command_download_notification_channel_description">إشعار يُظهر مستوى التقدم في تحميل ملفات الصوت والفيديو بإستخدام أوامر yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<string name="video_format">Video Format</string>
|
||||
<string name="audio_quality">Səs Keyfiyyəti</string>
|
||||
<string name="audio_quality_summary">0 (ən yaxşı) 10 (ən pis)</string>
|
||||
<string name="cancel_download">Yükləməni Ləğv Et</string>
|
||||
<string name="cancel_task">Yükləməni Ləğv Et</string>
|
||||
<string name="run_command">Əmri İşlət</string>
|
||||
<string name="command_download_notification_channel_name">Əmr Yükləmələri</string>
|
||||
<string name="command_download_notification_channel_description">Yt-dlp əmri işlədərkən yükləmə irəliləyişi göstərən bildiriş</string>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<string name="ytdl_already_updating">নতুন সংস্করণ ইনস্টল করা হচ্ছে</string>
|
||||
<string name="sponsorblock_fillers">ফিল্টার</string>
|
||||
<string name="sponsorblock_reminders">সদস্যতা রিমাইন্ডার</string>
|
||||
<string name="cancel_download">ডাউনলোড বাতিল করুন</string>
|
||||
<string name="cancel_task">ডাউনলোড বাতিল করুন</string>
|
||||
<string name="logs">লগ</string>
|
||||
<string name="in_queue">কিউ তে আছে</string>
|
||||
<string name="audio_quality">অডিও মান</string>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
<string name="video_format">ভিডিও ফরম্যাট</string>
|
||||
<string name="audio_quality">অডিও মান</string>
|
||||
<string name="audio_quality_summary">0 (সেরা) 10 (সবচেয়ে খারাপ)</string>
|
||||
<string name="cancel_download">ডাউনলোড বাতিল করুন</string>
|
||||
<string name="cancel_task">ডাউনলোড বাতিল করুন</string>
|
||||
<string name="run_command">কমান্ড চালু করুন</string>
|
||||
<string name="items_left">বাকি আইটেম(গুলি)</string>
|
||||
<string name="history_is_empty">ইতিহাস খালি</string>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<string name="save_thumb_summary">Uložit náhled ve složce stahování</string>
|
||||
<string name="command_download_notification_channel_name">Stažené příkazy</string>
|
||||
<string name="ytdl_already_updating">Instalace nové verze</string>
|
||||
<string name="cancel_download">Zrušit stahování</string>
|
||||
<string name="cancel_task">Zrušit stahování</string>
|
||||
<string name="audio_quality">Kvalita audia</string>
|
||||
<string name="audio_format">Audio formát</string>
|
||||
<string name="couldnt_find_apk">Nepodařilo se najít vhodný APK soubor</string>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
<string name="add_chapters">Kapitel in Videos</string>
|
||||
<string name="embed_thumb_summary">Verwende das Vorschaubild als Cover-Art</string>
|
||||
<string name="save_thumb">Vorschaubild speichern</string>
|
||||
<string name="cancel_download">Herunterladen abbrechen</string>
|
||||
<string name="cancel_task">Herunterladen abbrechen</string>
|
||||
<string name="you_are_going_to_delete">Löschen</string>
|
||||
<string name="incognito_summary">Herunterladen ohne es zum Verlauf hinzuzufügen</string>
|
||||
<string name="video_format">Videoformat</string>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
<string name="video_format">Μορφή Βίντεο</string>
|
||||
<string name="audio_quality">Ποιότητα Ήχου</string>
|
||||
<string name="audio_quality_summary">0 (καλύτερη) 10 (χειρότερη)</string>
|
||||
<string name="cancel_download">Ακύρωση Λήψης</string>
|
||||
<string name="cancel_task">Ακύρωση Λήψης</string>
|
||||
<string name="run_command">Εκτέλεση Εντολής</string>
|
||||
<string name="command_download_notification_channel_name">Λήψεις Εντολών</string>
|
||||
<string name="command_download_notification_channel_description">Ειδοποίηση που δείχνει την πρόοδο της λήψης με χρήση μιας εντολής yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
<string name="download">Descargar</string>
|
||||
<string name="save_thumb">Guardar Miniatura</string>
|
||||
<string name="save_thumb_summary">Guarda la miniatura en el directorio de descarga</string>
|
||||
<string name="cancel_download">Cancelar Descarga</string>
|
||||
<string name="cancel_task">Cancelar Descarga</string>
|
||||
<string name="video_quality">Calidad de Video</string>
|
||||
<string name="video_format">Formato de Video</string>
|
||||
<string name="audio_quality">Calidad de Audio</string>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<string name="save_thumb">ذخیره تصویر بندانگشتی</string>
|
||||
<string name="audio_format">فرمت صدا</string>
|
||||
<string name="video_format">فرمت ویدئو</string>
|
||||
<string name="cancel_download">لغو دانلود</string>
|
||||
<string name="cancel_task">لغو دانلود</string>
|
||||
<string name="run_command">اجرای دستور</string>
|
||||
<string name="command_download_notification_channel_name">دستور دانلودها</string>
|
||||
<string name="command_download_notification_channel_description">اعلان پیشرفت دانلود با استفاده از دستور yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<string name="video_format">Format vidéo</string>
|
||||
<string name="audio_quality">Qualité audio</string>
|
||||
<string name="audio_quality_summary">0 (meilleur) 10 (pire)</string>
|
||||
<string name="cancel_download">Annuler le téléchargement</string>
|
||||
<string name="cancel_task">Annuler le téléchargement</string>
|
||||
<string name="run_command">Exécuter la commande</string>
|
||||
<string name="command_download_notification_channel_name">Téléchargements de commandes</string>
|
||||
<string name="command_download_notification_channel_description">Notification indiquant la progression du téléchargement à l\'aide d\'une commande yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@
|
|||
<string name="finished_download_notification_channel_description">पूर्ण डाउनलोड के लिए नोटीफिकेशन</string>
|
||||
<string name="quick_download">त्वरित डाउनलोड</string>
|
||||
<string name="quick_download_summary">डाउनलोड कार्ड में डेटा न लाएं</string>
|
||||
<string name="cancel_download">डाउनलोड रद्द करें</string>
|
||||
<string name="cancel_task">डाउनलोड रद्द करें</string>
|
||||
<string name="command_download_notification_channel_name">कमांड डाउनलोड</string>
|
||||
<string name="command_download_notification_channel_description">yt-dlp कमांड का उपयोग करके डाउनलोडिंग की प्रगति दिखाने वाली अधिसूचना</string>
|
||||
<string name="url">यूआरएल</string>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<string name="ytdl_already_updating">Új verzió telepítése</string>
|
||||
<string name="sponsorblock_fillers">Fiók</string>
|
||||
<string name="sponsorblock_reminders">Előfizetési emlékeztetők</string>
|
||||
<string name="cancel_download">Letöltés megszakítása</string>
|
||||
<string name="cancel_task">Letöltés megszakítása</string>
|
||||
<string name="logs">Naplók</string>
|
||||
<string name="audio_quality">Audio minőség</string>
|
||||
<string name="audio_format">Audio formátum</string>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
<string name="audio_format">Format Audio</string>
|
||||
<string name="audio_quality">Kualitas Audio</string>
|
||||
<string name="audio_quality_summary">0 (terbaik) 10 (terburuk)</string>
|
||||
<string name="cancel_download">Batalkan Pengunduhan</string>
|
||||
<string name="cancel_task">Batalkan Pengunduhan</string>
|
||||
<string name="api_key">Gunakan Kunci API</string>
|
||||
<string name="ytdl_version">Versi yt-dlp</string>
|
||||
<string name="Open_File">Buka Berkas</string>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
<string name="video_format">Formato video</string>
|
||||
<string name="audio_quality">Qualità audio</string>
|
||||
<string name="audio_quality_summary">0 (migliore) 10 (peggiore)</string>
|
||||
<string name="cancel_download">Annulla download</string>
|
||||
<string name="cancel_task">Annulla download</string>
|
||||
<string name="run_command">Esegui comando</string>
|
||||
<string name="command_download_notification_channel_name">Download di comandi</string>
|
||||
<string name="command_download_notification_channel_description">Notifica che mostra l\'avanzamento del download utilizzando un comando yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<string name="sponsorblock_intro">פתיח</string>
|
||||
<string name="ytdl_already_updating">מעדכן גירסה חדשה</string>
|
||||
<string name="sponsorblock_reminders">הזכרות הרשמה</string>
|
||||
<string name="cancel_download">בטל הורדה</string>
|
||||
<string name="cancel_task">בטל הורדה</string>
|
||||
<string name="audio_quality">איכות אודיו</string>
|
||||
<string name="audio_format">פורמט אודיו</string>
|
||||
<string name="title">כותרת</string>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
<string name="audio">音声</string>
|
||||
<string name="aria2_summary">ダウンローダーとして Aria2c を使用します</string>
|
||||
<string name="audio_quality">音質</string>
|
||||
<string name="cancel_download">ダウンロードをキャンセル</string>
|
||||
<string name="cancel_task">ダウンロードをキャンセル</string>
|
||||
<string name="save_thumb">サムネイルを保存</string>
|
||||
<string name="add_chapters_summary">YouTube / SponsorBlock の登録シーンを動画のチャプターとして表示</string>
|
||||
<string name="run_command">コマンドを実行</string>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
<string name="aria2_summary">기본값 대신 aria2c를 다운로더로 사용</string>
|
||||
<string name="embed_subs_summary">비디오에 자막 추가</string>
|
||||
<string name="audio_quality_summary">최고 (0) 최저 (10)</string>
|
||||
<string name="cancel_download">다운로드 취소</string>
|
||||
<string name="cancel_task">다운로드 취소</string>
|
||||
<string name="command_download_notification_channel_name">명령 다운로드</string>
|
||||
<string name="items_left">항목 남음</string>
|
||||
<string name="history_is_empty">기록이 비어 있습니다</string>
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@
|
|||
<string name="home">Sākums</string>
|
||||
<string name="title">Nosaukums</string>
|
||||
<string name="video_format">Video Formāts</string>
|
||||
<string name="cancel_download">Atcelt Lejupielādi</string>
|
||||
<string name="cancel_task">Atcelt Lejupielādi</string>
|
||||
<string name="limit_rate_summary">Maksimālais lejupielādes ātrums (baitos sekundē), piem., 50K vai 4.2M</string>
|
||||
<string name="aria2_summary">Izmantot aria2c kā lejupielādētāju, nevis noklusējuma</string>
|
||||
<string name="add_chapters_summary">Atzīmē YouTube / SponsorBlock segmentus kā video nodaļas</string>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<string name="embed_thumb">Miniatyrbildeomslag</string>
|
||||
<string name="save_thumb_summary">Lagre miniatyrbildet i nedlastingsmappen</string>
|
||||
<string name="audio_quality_summary">0 (best) 10 (verst)</string>
|
||||
<string name="cancel_download">Avbryt nedlasting</string>
|
||||
<string name="cancel_task">Avbryt nedlasting</string>
|
||||
<string name="command_download_notification_channel_description">Merknad som viser nedlastingsfremdrift for bruk av yt-dlp -kommando</string>
|
||||
<string name="history_is_empty">Historikken er tom.</string>
|
||||
<string name="api_key_summary">Raskere resultater fra YouTube</string>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<string name="command_download_notification_channel_name">Commando Downloads</string>
|
||||
<string name="sponsorblock_intro">Intro</string>
|
||||
<string name="ytdl_already_updating">Nieuwe versie aan het installeren</string>
|
||||
<string name="cancel_download">Download Annuleren</string>
|
||||
<string name="cancel_task">Download Annuleren</string>
|
||||
<string name="audio_quality">Audio Kwaliteit</string>
|
||||
<string name="audio_format">Audio Formaat</string>
|
||||
<string name="title">Titel</string>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
<string name="save_thumb_summary">Gøym småbilete i lag med videoar/lydar</string>
|
||||
<string name="audio_format">Lydformat</string>
|
||||
<string name="embed_subs_summary">Bygg inn undertekster i videoar</string>
|
||||
<string name="cancel_download">Avbryt hentinga</string>
|
||||
<string name="cancel_task">Avbryt hentinga</string>
|
||||
<string name="run_command">Køyr påbod</string>
|
||||
<string name="command_download_notification_channel_name">Henta med påbod</string>
|
||||
<string name="command_download_notification_channel_description">Varsel som viser kvar langt hentingar med yt-dlp-påbod har kome</string>
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
<string name="run_command">ਕਮਾਂਡ ਚਲਾਓ</string>
|
||||
<string name="command_download_notification_channel_description">ਇੱਕ yt-dlp ਕਮਾਂਡ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਪ੍ਰਗਤੀ ਨੂੰ ਦਰਸਾਉਂਦਾ ਨੋਟੀਫਿਕੇਸ਼ਨ</string>
|
||||
<string name="sort_by">ਛਾਂਟੀ</string>
|
||||
<string name="cancel_download">ਡਾਊਨਲੋਡ ਰੱਦ ਕਰੋ</string>
|
||||
<string name="cancel_task">ਡਾਊਨਲੋਡ ਰੱਦ ਕਰੋ</string>
|
||||
<string name="command_download_notification_channel_name">ਕਮਾਂਡ ਡਾਊਨਲੋਡ</string>
|
||||
<string name="link_copied_to_clipboard">ਲਿੰਕ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ</string>
|
||||
<string name="api_key">API ਕੁੰਜੀ ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
<string name="audio_format">Format dźwięku</string>
|
||||
<string name="video_format">Format filmu</string>
|
||||
<string name="audio_quality_summary">0 (najlepsze) 10 (najgorsze)</string>
|
||||
<string name="cancel_download">Anuluj pobieranie</string>
|
||||
<string name="cancel_task">Anuluj pobieranie</string>
|
||||
<string name="command_download_notification_channel_name">Pobrania przy użyciu poleceń</string>
|
||||
<string name="history_is_empty">Historia jest pusta</string>
|
||||
<string name="you_are_going_to_delete">Usuwanie</string>
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
<string name="author">Autor</string>
|
||||
<string name="run_command">Executar comando</string>
|
||||
<string name="audio_quality_summary">0 (melhor) 10 (pior)</string>
|
||||
<string name="cancel_download">Cancelar download</string>
|
||||
<string name="cancel_task">Cancelar download</string>
|
||||
<string name="update_app_summary">Verifica se há atualizações ao iniciar o aplicativo</string>
|
||||
<string name="configure_download">Ajustar download</string>
|
||||
<string name="save_thumb_summary">Salve a miniatura na pasta de download</string>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
<string name="audio">Áudio</string>
|
||||
<string name="save_thumb">Guardar miniatura</string>
|
||||
<string name="save_thumb_summary">Guardar miniatura na pasta de descargas</string>
|
||||
<string name="cancel_download">Cancelar descarga</string>
|
||||
<string name="cancel_task">Cancelar descarga</string>
|
||||
<string name="run_command">Executar comando</string>
|
||||
<string name="command_download_notification_channel_name">Comando e descargas</string>
|
||||
<string name="command_download_notification_channel_description">Notificação que mostra o progresso das descargas usando um comando yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
<string name="export_from_clipboard">Exportă în clipboard</string>
|
||||
<string name="create_template">Creați un șablon</string>
|
||||
<string name="audio_quality">Calitate audio</string>
|
||||
<string name="cancel_download">Anulați descărcarea</string>
|
||||
<string name="cancel_task">Anulați descărcarea</string>
|
||||
<string name="defaultValue">Valoare implicită</string>
|
||||
<string name="template">Șablon</string>
|
||||
<string name="date_added">Data adăugării</string>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
<string name="video_format">Видео формат</string>
|
||||
<string name="audio_quality">Качество аудио</string>
|
||||
<string name="audio_quality_summary">0 (лучшее) 10 (худшее)</string>
|
||||
<string name="cancel_download">Отменить загрузку</string>
|
||||
<string name="cancel_task">Отменить загрузку</string>
|
||||
<string name="run_command">Запустить команду</string>
|
||||
<string name="items_left">фрагмент(ов) осталось</string>
|
||||
<string name="you_are_going_to_delete">Удаление</string>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<resources>
|
||||
<string name="save_thumb_summary">Uložiť miniatúru do priečinka prevzatých súborov</string>
|
||||
<string name="ytdl_already_updating">Inštaluje sa nová verzia</string>
|
||||
<string name="cancel_download">Zrušiť Sťahovanie</string>
|
||||
<string name="cancel_task">Zrušiť Sťahovanie</string>
|
||||
<string name="audio_quality">Kvalita Zvuku</string>
|
||||
<string name="audio_format">Formát Zvuku</string>
|
||||
<string name="music_directory">Hudobný priečinok</string>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
<string name="video_format">Formati i Videos</string>
|
||||
<string name="audio_quality">Kualiteti i Audios</string>
|
||||
<string name="audio_quality_summary">0 (Më i miri) 10 (Më i keqi)</string>
|
||||
<string name="cancel_download">Anulo Shkarkimin</string>
|
||||
<string name="cancel_task">Anulo Shkarkimin</string>
|
||||
<string name="run_command">Ekzekuto Komandën</string>
|
||||
<string name="command_download_notification_channel_name">Shkarkimet e Skedarëve nga Komanda</string>
|
||||
<string name="command_download_notification_channel_description">Njoftimi i cili tregon progresin e shkarkimeve te skedarëve audio dhe video nga komanda</string>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<string name="embed_metadata_summary">Рашчланите и уградите метаподатке у фајл аудио снимка</string>
|
||||
<string name="sponsorblock_fillers">Попуњавања</string>
|
||||
<string name="sponsorblock_reminders">Подсетници о праћењу</string>
|
||||
<string name="cancel_download">Откажи преузимање</string>
|
||||
<string name="cancel_task">Откажи преузимање</string>
|
||||
<string name="logs">Евиденције</string>
|
||||
<string name="export_file">Извези фајл</string>
|
||||
<string name="in_queue">У редоследу</string>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<string name="audio_format">รูปแบบเสียง</string>
|
||||
<string name="video_format">รูปแบบวิดีโอ</string>
|
||||
<string name="audio_quality">คุณภาพเสียง</string>
|
||||
<string name="cancel_download">ยกเลิกการดาวน์โหลด</string>
|
||||
<string name="cancel_task">ยกเลิกการดาวน์โหลด</string>
|
||||
<string name="run_command">เรียกใช้คำสั่ง</string>
|
||||
<string name="items_left">รายการที่เหลือ</string>
|
||||
<string name="history_is_empty">ประวัติว่างเปล่า</string>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<string name="video_format">Video Formatı</string>
|
||||
<string name="audio_quality">Ses Kalitesi</string>
|
||||
<string name="audio_quality_summary">0 (en iyi) 10 (en kötü)</string>
|
||||
<string name="cancel_download">İndirmeyi İptal Et</string>
|
||||
<string name="cancel_task">İndirmeyi İptal Et</string>
|
||||
<string name="run_command">Komutu Çalıştır</string>
|
||||
<string name="command_download_notification_channel_name">Komut İndirmeleri</string>
|
||||
<string name="command_download_notification_channel_description">Yt-dlp komutu kullanarak indirme işlemi ilerleyişini gösteren bildirim</string>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
<string name="audio_format">Формат аудіо</string>
|
||||
<string name="save_thumb_summary">Зберегти мініатюру в папці завантаження</string>
|
||||
<string name="audio_quality_summary">0 (найкраще) 10 (найгірше)</string>
|
||||
<string name="cancel_download">Скасувати завантаження</string>
|
||||
<string name="cancel_task">Скасувати завантаження</string>
|
||||
<string name="run_command">Виконати команду</string>
|
||||
<string name="command_download_notification_channel_name">Команда завантажує</string>
|
||||
<string name="items_left">елементів залишилося</string>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<string name="video_format">Định dạng cuộn băng</string>
|
||||
<string name="audio_quality">Chất lượng âm thanh</string>
|
||||
<string name="audio_quality_summary">0 (tốt nhất) 10 (tệ nhất)</string>
|
||||
<string name="cancel_download">Hủy tải xuống</string>
|
||||
<string name="cancel_task">Hủy tải xuống</string>
|
||||
<string name="run_command">Chạy lệnh</string>
|
||||
<string name="command_download_notification_channel_name">Lệnh tải xuống</string>
|
||||
<string name="command_download_notification_channel_description">Thông báo hiển thị tiến trình tải xuống bằng lệnh yt-dlp</string>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
<string name="embed_thumb">缩略图封面</string>
|
||||
<string name="save_thumb">保存缩略图</string>
|
||||
<string name="video_format">视频格式</string>
|
||||
<string name="cancel_download">取消下载</string>
|
||||
<string name="cancel_task">取消下载</string>
|
||||
<string name="you_are_going_to_delete">删除</string>
|
||||
<string name="downloads">下载</string>
|
||||
<string name="sort_by">排序</string>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
<string name="add_chapters">影片章節</string>
|
||||
<string name="save_thumb_summary">將縮圖保存在下載資料夾中</string>
|
||||
<string name="audio_format">音訊格式</string>
|
||||
<string name="cancel_download">取消下載</string>
|
||||
<string name="cancel_task">取消下載</string>
|
||||
<string name="run_command">執行命令</string>
|
||||
<string name="link_copied_to_clipboard">連結已複製到剪貼簿</string>
|
||||
<string name="api_key">使用 API 金鑰</string>
|
||||
|
|
|
|||
|
|
@ -1086,6 +1086,7 @@
|
|||
<item>@string/saved</item>
|
||||
<item>@string/command_templates</item>
|
||||
<item>@string/cookies</item>
|
||||
<item>@string/multiple_download_card</item>
|
||||
</array>
|
||||
|
||||
<array name="swipe_gestures_values">
|
||||
|
|
@ -1096,6 +1097,7 @@
|
|||
<item>saved</item>
|
||||
<item>templates</item>
|
||||
<item>cookies</item>
|
||||
<item>multipledownloadcard</item>
|
||||
</array>
|
||||
|
||||
<array name="ytdlp_source">
|
||||
|
|
@ -1335,4 +1337,17 @@
|
|||
<item>Zulu</item>
|
||||
</string-array>
|
||||
|
||||
<array name="format_filtering">
|
||||
<item>@string/all</item>
|
||||
<item>@string/suggested</item>
|
||||
<item>@string/format_smallest</item>
|
||||
</array>
|
||||
|
||||
|
||||
<array name="format_filtering_values">
|
||||
<item>ALL</item>
|
||||
<item>SUGGESTED</item>
|
||||
<item>SMALLEST</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
<string name="video_format">Video Format</string>
|
||||
<string name="audio_quality">Audio Quality</string>
|
||||
<string name="audio_quality_summary">0 (best) 10 (worst)</string>
|
||||
<string name="cancel_download">Cancel Download</string>
|
||||
<string name="cancel_task">Cancel Task</string>
|
||||
<string name="run_command">Run Command</string>
|
||||
<string name="command_download_notification_channel_name">Command Downloads</string>
|
||||
<string name="command_download_notification_channel_description">Notification showing the progress of downloading using a yt-dlp command</string>
|
||||
|
|
@ -85,8 +85,8 @@
|
|||
<string name="video_quality">Video Quality</string>
|
||||
<string name="embed_subtitles">Embed Subtitles</string>
|
||||
<string name="add_chapter">Add Chapters</string>
|
||||
<string name="show_download_card">Show Options for Downloading</string>
|
||||
<string name="download_card_summary">Settings for how to download items</string>
|
||||
<string name="show_download_card">Show Download Card</string>
|
||||
<string name="download_card_summary">Modify settings for that item before downloading. Disabling this option starts the download immediately</string>
|
||||
<string name="Open_File">Open File</string>
|
||||
<string name="you_are_going_to_delete_multiple_items">Deleting multiple items</string>
|
||||
<string name="delete_file_too">Delete the file from the device</string>
|
||||
|
|
@ -331,4 +331,11 @@
|
|||
<string name="source">Source</string>
|
||||
<string name="app">App</string>
|
||||
<string name="cut_unavailable">You need to update the item data in order to be able to use cut feature</string>
|
||||
<string name="changed_path_for_everyone_to">Changed every item\'s download path to:</string>
|
||||
<string name="dismiss">Dismiss</string>
|
||||
<string name="all">All</string>
|
||||
<string name="generic">Generic</string>
|
||||
<string name="multiple_download_card">Multiple Download Card</string>
|
||||
<string name="format_filter">Format Filter</string>
|
||||
<string name="format_smallest">Smallest format (per Resolution)</string>
|
||||
</resources>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
app:title="@string/ytdl_version"/>
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="nightly"
|
||||
android:defaultValue="stable"
|
||||
android:entries="@array/ytdlp_source"
|
||||
android:entryValues="@array/ytdlp_source_values"
|
||||
android:icon="@drawable/baseline_source_24"
|
||||
|
|
@ -49,6 +49,15 @@
|
|||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/format_order" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="all"
|
||||
android:entries="@array/format_filtering"
|
||||
android:entryValues="@array/format_filtering_values"
|
||||
android:icon="@drawable/baseline_align_horizontal_left_24"
|
||||
app:key="format_filter"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/format_filter" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
|
|
|
|||
17
fastlane/metadata/android/en-US/changelogs/10720.txt
Normal file
17
fastlane/metadata/android/en-US/changelogs/10720.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
## What's New
|
||||
- Increased the height of the history card a slight bit
|
||||
- Fixed app not using the -S format sorter in normal GUI downloads
|
||||
- Added the multiple download card as an option to disable the swipe gestures
|
||||
- Added a recyclerview to the search results because they were buggy before and would not show sometimes
|
||||
- Added a new history item card design in cases if you quick-downloaded a playlist or if you made multiple cuts of a file. Instead of being separate, they are bundled and you can share them all at once and if you want to open the file a new dialog will show telling you to choose which one. If any of them is deleted, they are greyed out
|
||||
- Fixed the shortcuts behaviour by allowing duplicate shortcuts to be added to textbox and to not check
|
||||
- Added format filtering in the format list bottom sheet. You can filter between ALL, SUGGESTED, SMALLEST, GENERIC. Suggested formats are built upon your app preferences like your preferred codec, container, quality. Smallest formats are all formats for each resolution with the smallest filesize. Generic are formats you see if an item has not updated the formats yet, in case you want to use those for some reason
|
||||
- Added clipboard button right in the home screen for quick access to the url you copied instead of going to the searchview. That item is also available there aswell
|
||||
- Added ability to show the URL in a history item if the download produced no title for it
|
||||
- Added zoom-in zoom-out slider for logs and terminal screens.
|
||||
- Added more options of datafetching for titles and authors, like track, alt_title to avoid the default youtube naming scheme when available. Useful for audio downloads
|
||||
- Since some people are confused. In the download card each tab item is independent and they each create a distinct download item and when you press download the app picks from the tab you are currently. If you want to select the audio format in the video tab you can just open the format list and scroll to the bottom for the audio formats. You can select multiple if you want and then press ok. But since some people thought that selecting the audio in audio tab would apply to the video tab, i added the ability to synchronise that format automatically in case people dont know about this lol
|
||||
- Other small bug fixes
|
||||
|
||||
The history item has been updated in this version so old backups will not work. Please make a backup of your stuff in the settings before updating. In case this update fails, notify people in telegram and revert back to the past version and use your backup and also give us the backup to reproduce the error if it happens.
|
||||
Happy Downloading & Happy belated New Year :)
|
||||
Loading…
Reference in a new issue