mirror of https://github.com/deniscerri/ytdlnis
alot of stuff
- include search history when searching - removed scroll bug from command tab - added spacing between command template title and ok button in selection card - made download progress not dublicate in terminal - made ability to store terminal state - added ability to create multiple terminal instances and show them as a list similar to download queue - fixed thumbnail download not working - fixed app crashing when clicking on format updated notification - fixed app crashing when double clicking format on multiple download card - added custom sponsorblock api preference - removed contextual app bar when you its enabled and the user taps the log button in the erorred tab - made app always show quick download card and asynchoronously load data. Quick Download now if its on, it wont load data at all - added shimmer when loading data in the download card - fixed app showing no formats if there were no common formats. Now it will give you generic formats - made open command template list be half the screen, shortcuts third of the screen so the user can see what its being added - fixed sometimes app slipping queued downloads even though its told to pause all - fixed trim filenames cutting files too short - made mediastore scanning of files one by one - fixed filename template not working in multiple download card - fixed -F in terminal not being inline - added preferred audio codec - made auto update on boot if there are no active downloads - fixed format text overlapping - added a new error activity dialog in cases yt-dlp data fetching in the home screen fails. You can copy the logpull/299/head
parent
a31f3f0804
commit
25a09e7604
@ -0,0 +1,544 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 10,
|
||||||
|
"identityHash": "6b5efd73749a7138035e1f00349715c8",
|
||||||
|
"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, `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": "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)",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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)",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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)",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "command",
|
||||||
|
"columnName": "command",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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, '6b5efd73749a7138035e1f00349715c8')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package com.deniscerri.ytdlnis.adapter
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
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.TerminalItem
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
|
||||||
|
class TerminalDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<TerminalItem?, TerminalDownloadsAdapter.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) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val cardView: MaterialCardView
|
||||||
|
|
||||||
|
init {
|
||||||
|
cardView = itemView.findViewById(R.id.active_download_card_view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val cardView = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.active_terminal_card, parent, false)
|
||||||
|
return ViewHolder(cardView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val item = getItem(position)
|
||||||
|
val card = holder.cardView
|
||||||
|
card.tag = "${item!!.id}##card"
|
||||||
|
|
||||||
|
// PROGRESS BAR ----------------------------------------------------
|
||||||
|
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
||||||
|
progressBar.tag = "${item.id}##progress"
|
||||||
|
progressBar.progress = 0
|
||||||
|
progressBar.isIndeterminate = true
|
||||||
|
|
||||||
|
// COMMAND ----------------------------------
|
||||||
|
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||||
|
itemTitle.text = item.command.trim()
|
||||||
|
|
||||||
|
//OUTPUT
|
||||||
|
val output = card.findViewById<TextView>(R.id.output)
|
||||||
|
output.tag = "${item.id}##output"
|
||||||
|
|
||||||
|
// STOP BUTTON ----------------------------------
|
||||||
|
val stopButton = card.findViewById<MaterialButton>(R.id.active_download_stop)
|
||||||
|
if (stopButton.hasOnClickListeners()) stopButton.setOnClickListener(null)
|
||||||
|
stopButton.setOnClickListener {onItemClickListener.onCancelClick(item.id)}
|
||||||
|
|
||||||
|
card.setOnClickListener {
|
||||||
|
onItemClickListener.onCardClick(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interface OnItemClickListener {
|
||||||
|
fun onCancelClick(itemID: Long)
|
||||||
|
fun onCardClick(item: TerminalItem)
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<TerminalItem> = object : DiffUtil.ItemCallback<TerminalItem>() {
|
||||||
|
override fun areItemsTheSame(oldItem: TerminalItem, newItem: TerminalItem): Boolean {
|
||||||
|
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||||
|
return ranged[0] == ranged[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: TerminalItem, newItem: TerminalItem): Boolean {
|
||||||
|
return oldItem.command == newItem.command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import androidx.room.*
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||||
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface TerminalDao {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM terminalDownloads ORDER BY id")
|
||||||
|
fun getActiveTerminalDownloads() : List<TerminalItem>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM terminalDownloads ORDER BY id")
|
||||||
|
fun getActiveTerminalDownloadsFlow() : Flow<List<TerminalItem>>
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM terminalDownloads")
|
||||||
|
fun getActiveTerminalsCount() : Int
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(item: TerminalItem) : Long
|
||||||
|
|
||||||
|
@Query("DELETE from terminalDownloads WHERE id=:id")
|
||||||
|
suspend fun delete(id: Long)
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
@Entity(tableName = "terminalDownloads")
|
||||||
|
data class TerminalItem(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0,
|
||||||
|
var command: String
|
||||||
|
)
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package com.deniscerri.ytdlnis.database.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.asLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkInfo
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.await
|
||||||
|
import com.deniscerri.ytdlnis.App
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.TerminalDao
|
||||||
|
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
||||||
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||||
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
||||||
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
|
import com.deniscerri.ytdlnis.work.AlarmScheduler
|
||||||
|
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||||
|
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||||
|
private val dbManager: DBManager = DBManager.getInstance(application)
|
||||||
|
private val dao: TerminalDao = dbManager.terminalDao
|
||||||
|
private val notificationUtil = NotificationUtil(application)
|
||||||
|
fun getCount() : Int{
|
||||||
|
return dao.getActiveTerminalsCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTerminals() : Flow<List<TerminalItem>> {
|
||||||
|
return dao.getActiveTerminalDownloadsFlow()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun insert(item: TerminalItem) : Long {
|
||||||
|
return dao.insert(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun delete(id: Long) = CoroutineScope(Dispatchers.IO).launch{
|
||||||
|
dao.delete(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startTerminalDownloadWorker(item: TerminalItem) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val workRequest = OneTimeWorkRequestBuilder<TerminalDownloadWorker>()
|
||||||
|
.setInputData(
|
||||||
|
Data.Builder()
|
||||||
|
.putInt("id", item.id.toInt())
|
||||||
|
.putString("command", item.command)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addTag("terminal")
|
||||||
|
.addTag(item.id.toString())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
WorkManager.getInstance(application).beginUniqueWork(
|
||||||
|
item.id.toString(),
|
||||||
|
ExistingWorkPolicy.KEEP,
|
||||||
|
workRequest
|
||||||
|
).enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelTerminalDownload(id: Long) = CoroutineScope(Dispatchers.IO).launch{
|
||||||
|
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||||
|
WorkManager.getInstance(application).cancelUniqueWork(id.toString())
|
||||||
|
Thread.sleep(200)
|
||||||
|
notificationUtil.cancelDownloadNotification(id.toInt())
|
||||||
|
delete(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package com.deniscerri.ytdlnis.ui
|
||||||
|
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.elevation.SurfaceColors
|
||||||
|
|
||||||
|
open class ErrorDialogActivity : BaseActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
val title = intent.extras?.getString("title") ?: ""
|
||||||
|
val message = intent.extras?.getString("message") ?: ""
|
||||||
|
|
||||||
|
ThemeUtil.updateTheme(this)
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
|
||||||
|
v.setPadding(0, 0, 0, 0)
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
window.run {
|
||||||
|
setBackgroundDrawable(ColorDrawable(0))
|
||||||
|
setLayout(
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT
|
||||||
|
)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
|
||||||
|
} else {
|
||||||
|
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val errDialog = MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setIcon(R.drawable.ic_cancel)
|
||||||
|
.setPositiveButton(getString(R.string.copy_log)) { _: DialogInterface?, _: Int ->
|
||||||
|
val clipboard: ClipboardManager =
|
||||||
|
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
clipboard.setText(message)
|
||||||
|
this.finish()
|
||||||
|
}.setOnDismissListener {
|
||||||
|
this.finish()
|
||||||
|
}
|
||||||
|
errDialog.show()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||||
|
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
|
||||||
|
interface GUISync {
|
||||||
|
fun updateTitleAuthor(t: String, a: String)
|
||||||
|
fun updateUI(res: ResultItem?)
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package com.deniscerri.ytdlnis.ui.downloadcard
|
|
||||||
|
|
||||||
interface TitleAuthorSync {
|
|
||||||
fun updateTitleAuthor(t: String, a: String)
|
|
||||||
}
|
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package com.deniscerri.ytdlnis.ui.more.terminal
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.NavArgument
|
||||||
|
import androidx.navigation.NavGraph
|
||||||
|
import androidx.navigation.NavType
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
||||||
|
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalActivity : BaseActivity() {
|
||||||
|
private lateinit var terminalViewModel: TerminalViewModel
|
||||||
|
private lateinit var navHostFragment: NavHostFragment
|
||||||
|
private var downloadID by Delegates.notNull<Long>()
|
||||||
|
private lateinit var graph: NavGraph
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_terminal)
|
||||||
|
terminalViewModel = ViewModelProvider(this)[TerminalViewModel::class.java]
|
||||||
|
downloadID = savedInstanceState?.getLong("downloadID") ?: 0L
|
||||||
|
handleIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
handleIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleIntent(intent: Intent) {
|
||||||
|
val action = intent.action
|
||||||
|
val type = intent.type
|
||||||
|
Log.e(TAG, "$action $type")
|
||||||
|
var text : String? = null
|
||||||
|
if (action == Intent.ACTION_SEND && type != null) {
|
||||||
|
Log.e(TAG, action)
|
||||||
|
text = if (intent.getStringExtra(Intent.EXTRA_TEXT) == null){
|
||||||
|
val uri = if (Build.VERSION.SDK_INT >= 33){
|
||||||
|
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
|
||||||
|
}else{
|
||||||
|
intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||||
|
}
|
||||||
|
"-a \"${FileUtil.formatPath(uri?.path ?: "")}\""
|
||||||
|
}else{
|
||||||
|
intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navHostFragment = supportFragmentManager.findFragmentById(R.id.frame_layout) as NavHostFragment
|
||||||
|
graph = navHostFragment.navController.navInflater.inflate(R.navigation.terminal_graph)
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val count = withContext(Dispatchers.IO){
|
||||||
|
terminalViewModel.getCount()
|
||||||
|
}
|
||||||
|
val bundle = Bundle()
|
||||||
|
if (count == 0){
|
||||||
|
bundle.putString("share", text ?: "")
|
||||||
|
graph.setStartDestination(R.id.terminalFragment)
|
||||||
|
graph.findNode(graph.startDestinationId)?.addArgument("share", NavArgument.Builder()
|
||||||
|
.setType(NavType.StringType)
|
||||||
|
.setDefaultValue(text ?: "")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
navHostFragment.navController.setGraph(graph, bundle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "TerminalActivity"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.deniscerri.ytdlnis.ui.more.terminal
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.HorizontalScrollView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.activity.addCallback
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.view.forEach
|
||||||
|
import androidx.core.view.get
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.work.WorkInfo
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkQuery
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.adapter.TerminalDownloadsAdapter
|
||||||
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
||||||
|
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||||
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalDownloadsListFragment : Fragment(), TerminalDownloadsAdapter.OnItemClickListener {
|
||||||
|
private var topAppBar: MaterialToolbar? = null
|
||||||
|
private lateinit var terminalViewModel: TerminalViewModel
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
terminalViewModel = ViewModelProvider(this)[TerminalViewModel::class.java]
|
||||||
|
return inflater.inflate(R.layout.fragment_terminal_download_list, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val recycler = view.findViewById<RecyclerView>(R.id.terminal_recycler)
|
||||||
|
val adapter = TerminalDownloadsAdapter(this@TerminalDownloadsListFragment, requireActivity())
|
||||||
|
recycler.adapter = adapter
|
||||||
|
recycler.enableFastScroll()
|
||||||
|
recycler.layoutManager = GridLayoutManager(requireContext(), resources.getInteger(R.integer.grid_size))
|
||||||
|
topAppBar = requireActivity().findViewById(R.id.custom_command_toolbar)
|
||||||
|
topAppBar!!.setNavigationOnClickListener { requireActivity().finish() }
|
||||||
|
topAppBar?.menu?.forEach { it.isVisible = false }
|
||||||
|
topAppBar?.menu?.get(0)?.isVisible = true
|
||||||
|
|
||||||
|
topAppBar?.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
|
when(m.itemId){
|
||||||
|
R.id.add -> {
|
||||||
|
findNavController().navigate(R.id.terminalFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
terminalViewModel.getTerminals().collectLatest {
|
||||||
|
adapter.submitList(it)
|
||||||
|
if (it.isEmpty()){
|
||||||
|
findNavController().navigate(R.id.terminalFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkManager.getInstance(requireContext())
|
||||||
|
.getWorkInfosByTagLiveData("terminal")
|
||||||
|
.observe(viewLifecycleOwner){ list ->
|
||||||
|
list.forEach {work ->
|
||||||
|
if (work == null) return@forEach
|
||||||
|
val id = work.progress.getInt("id", 0)
|
||||||
|
if(id == 0) return@forEach
|
||||||
|
|
||||||
|
val progress = work.progress.getInt("progress", 0)
|
||||||
|
val output = work.progress.getString("output")
|
||||||
|
|
||||||
|
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
||||||
|
val outputText = view.findViewWithTag<TextView>("$id##output")
|
||||||
|
|
||||||
|
requireActivity().runOnUiThread {
|
||||||
|
kotlin.runCatching {
|
||||||
|
progressBar?.setProgressCompat(progress, true)
|
||||||
|
outputText?.text = output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onCancelClick(itemID: Long) {
|
||||||
|
terminalViewModel.cancelTerminalDownload(itemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCardClick(item: TerminalItem) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putLong("id", item.id)
|
||||||
|
findNavController().navigate(R.id.terminalFragment, bundle)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
<?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_marginHorizontal="10dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintDimensionRatio="H,2:1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/active_download_card_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="20dp"
|
||||||
|
app:cardElevation="10dp"
|
||||||
|
app:cardMaxElevation="12dp"
|
||||||
|
android:checkable="true"
|
||||||
|
app:strokeWidth="0dp"
|
||||||
|
app:cardPreventCornerOverlap="true"
|
||||||
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
app:trackColor="#000"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:alpha="0.3"
|
||||||
|
android:scaleY="200"/>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:shadowColor="#000"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:shadowDx="4"
|
||||||
|
android:shadowDy="4"
|
||||||
|
android:shadowRadius="2"
|
||||||
|
android:textColor="#FFF"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/active_download_stop"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/active_download_stop"
|
||||||
|
style="?attr/materialIconButtonFilledStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
app:backgroundTint="?attr/colorSurface"
|
||||||
|
app:cornerRadius="15dp"
|
||||||
|
app:icon="@drawable/baseline_close_24"
|
||||||
|
app:iconSize="30dp"
|
||||||
|
app:iconTint="?android:textColorPrimary"
|
||||||
|
app:layout_constraintVertical_bias="0.0"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/barrier"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:barrierDirection="bottom"
|
||||||
|
app:constraint_referenced_ids="title,active_download_stop" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:focusable="true"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:maxLines="5"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:shadowColor="#000"
|
||||||
|
android:shadowDx="4"
|
||||||
|
android:shadowDy="4"
|
||||||
|
android:shadowRadius="2"
|
||||||
|
android:textColor="#FFF"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:gravity="bottom"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/barrier" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -1,121 +1,45 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.deniscerri.ytdlnis.ui.more.TerminalActivity">
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context=".ui.more.terminal.TerminalActivity">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:liftOnScroll="true"
|
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:liftOnScroll="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/custom_command_toolbar"
|
android:id="@+id/custom_command_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
android:elevation="0dp"
|
android:elevation="0dp"
|
||||||
app:title="@string/terminal"
|
|
||||||
app:menu="@menu/terminal_top_menu"
|
app:menu="@menu/terminal_top_menu"
|
||||||
android:layout_width="match_parent"
|
|
||||||
app:navigationIcon="@drawable/ic_back"
|
app:navigationIcon="@drawable/ic_back"
|
||||||
android:layout_height="match_parent"/>
|
app:title="@string/terminal" />
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
android:id="@+id/frame_layout"
|
||||||
android:layout_width="match_parent"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="0dp"
|
||||||
|
app:defaultNavHost="true"
|
||||||
<LinearLayout
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_width="match_parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_height="0dp"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:orientation="horizontal"
|
app:layout_constraintTop_toBottomOf="@id/appbar"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/coordinatorLayout"
|
app:navGraph="@navigation/terminal_graph" />
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/custom_command_scrollview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_margin="10dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:focusableInTouchMode="true"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
|
||||||
android:id="@+id/horizontalscroll_output"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/custom_command_output"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:scrollbars="horizontal|vertical"
|
|
||||||
android:scrollHorizontally="true"
|
|
||||||
android:textIsSelectable="true" />
|
|
||||||
|
|
||||||
</HorizontalScrollView>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/command_edittext"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:gravity="start"
|
|
||||||
android:inputType="textMultiLine|textNoSuggestions"
|
|
||||||
android:maxLines="100"
|
|
||||||
android:text="yt-dlp "
|
|
||||||
android:textSize="15sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
android:id="@+id/coordinatorLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
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"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
app:menu="@menu/terminal_menu" />
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
|
||||||
android:id="@+id/command_fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/run_command"
|
|
||||||
app:icon="@drawable/ic_baseline_keyboard_arrow_right_24"
|
|
||||||
app:layout_anchor="@id/bottomAppBar" />
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/terminal_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/custom_command_scrollview"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/coordinatorLayout"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/horizontalscroll_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/custom_command_output"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:scrollbars="horizontal|vertical"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/command_edittext"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:gravity="start"
|
||||||
|
android:inputType="textMultiLine|textNoSuggestions"
|
||||||
|
android:maxLines="10000"
|
||||||
|
android:text="yt-dlp "
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/coordinatorLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:menu="@menu/terminal_menu" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/command_fab"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/run_command"
|
||||||
|
app:icon="@drawable/ic_baseline_keyboard_arrow_right_24"
|
||||||
|
app:layout_anchor="@id/bottomAppBar" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/active_terminal_tasks"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/terminal_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation 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"
|
||||||
|
app:startDestination="@id/terminalDownloadsListFragment">
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/terminalDownloadsListFragment"
|
||||||
|
android:name="com.deniscerri.ytdlnis.ui.more.terminal.TerminalDownloadsListFragment"
|
||||||
|
tools:layout="@layout/fragment_terminal_downloadList"
|
||||||
|
android:label="TerminalDownloadsListFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_terminalDownloadsListFragment_to_terminalFragment2"
|
||||||
|
app:destination="@id/terminalFragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/terminalFragment"
|
||||||
|
android:name="com.deniscerri.ytdlnis.ui.more.terminal.TerminalFragment"
|
||||||
|
tools:layout="@layout/fragment_terminal"
|
||||||
|
android:label="TerminalFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_terminalFragment2_to_terminalDownloadsListFragment"
|
||||||
|
app:destination="@id/terminalDownloadsListFragment" />
|
||||||
|
</fragment>
|
||||||
|
</navigation>
|
||||||
@ -1,18 +1,19 @@
|
|||||||
# Project-wide Gradle settings.
|
## For more details on how to configure your build environment visit
|
||||||
# IDE (e.g. Android Studio) users:
|
|
||||||
# Gradle settings configured through the IDE *will override*
|
|
||||||
# any settings specified in this file.
|
|
||||||
# For more details on how to configure your build environment visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
#
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||||
|
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
|
#
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
#Sun Oct 08 20:53:48 CEST 2023
|
||||||
android.defaults.buildfeatures.buildconfig=true
|
android.defaults.buildfeatures.buildconfig=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.nonFinalResIds=false
|
android.nonFinalResIds=false
|
||||||
android.nonTransitiveRClass=false
|
android.nonTransitiveRClass=false
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1024M" -Dfile.encoding\=UTF-8
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
||||||
# org.gradle.parallel=true
|
|
||||||
|
|||||||
Loading…
Reference in New Issue