turned more files to kotlin

This commit is contained in:
Denis Çerri 2023-01-24 19:27:40 +01:00
parent 92d6b2f197
commit 6dc413cbd2
No known key found for this signature in database
GPG key ID: 95C43D517D830350
28 changed files with 578 additions and 855 deletions

View file

@ -320,7 +320,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/C:/Program%20Files/Android/Android%20Studio/plugins/android/lib/android.jar!/images/material/icons/materialicons/history/baseline_history_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/drag_handle/baseline_drag_handle_24.xml" />
</map>
</option>
</PersistentState>
@ -330,7 +330,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_history" />
<entry key="outputName" value="ic_handle" />
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
</map>
</option>

View file

@ -1,351 +0,0 @@
package com.deniscerri.ytdlnis.database;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.deniscerri.ytdlnis.database.models.HistoryItem;
import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.io.File;
import java.util.ArrayList;
public class DatabaseManager extends SQLiteOpenHelper {
Context context;
public static final String db_name = "ytdlnis_db";
public static final int db_version = 7;
public static final String results_table_name = "results";
public static final String history_table_name = "history";
public static final String id = "id";
public static final String videoId = "videoId";
public static final String url = "url";
public static final String title = "title";
public static final String author = "author";
public static final String duration = "duration";
public static final String thumb = "thumb";
public static final String downloadedAudio = "downloadedAudio";
public static final String downloadedVideo = "downloadedVideo";
public static final String type = "type";
public static final String time = "time";
public static final String isPlaylistItem = "isPlaylistItem";
public static final String website = "website";
public static final String downloadPath = "downloadPath";
public static final String downloadingAudio = "downloadingAudio";
public static final String downloadingVideo = "downloadingVideo";
public static final String playlistTitle = "playlistTitle";
public static final String isQueuedDownload = "isQueuedDownload";
public DatabaseManager(Context context){
super(context, db_name, null, db_version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String query = "CREATE TABLE " + results_table_name + " ("
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ videoId + " TEXT,"
+ url + " TEXT,"
+ title + " TEXT,"
+ author + " TEXT,"
+ duration + " TEXT,"
+ thumb + " TEXT,"
+ downloadedAudio + " INTEGER,"
+ downloadedVideo + " INTEGER,"
+ isPlaylistItem + " INTENGER,"
+ website + " TEXT,"
+ downloadingAudio + " INTEGER,"
+ downloadingVideo + " INTEGER,"
+ playlistTitle + " TEXT)";
sqLiteDatabase.execSQL(query);
query = "CREATE TABLE " + history_table_name + " ("
+ id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ url + " TEXT,"
+ title + " TEXT,"
+ author + " TEXT,"
+ duration + " TEXT,"
+ thumb + " TEXT,"
+ type + " TEXT,"
+ time + " TEXT,"
+ downloadPath + " TEXT,"
+ website + " TEXT,"
+ isQueuedDownload + " INTEGER)";
sqLiteDatabase.execSQL(query);
}
public void clearHistory(){
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DELETE FROM " + history_table_name);
//remove downloaded statuses from results
db.execSQL("UPDATE "+results_table_name+ " SET downloadedAudio=0, downloadedVideo=0" +
" WHERE downloadedAudio=1 OR downloadedVideo=1");
}
@SuppressLint("Range")
public void clearHistoryItem(HistoryItem video, boolean delete_file){
// SQLiteDatabase db = this.getWritableDatabase();
//
// if (delete_file){
// try{
// Cursor cursor = db.rawQuery("SELECT * FROM " + history_table_name + " WHERE url='" +
// video.getURL() + "' AND type='"+video.getDownloadedType() + "' LIMIT 1", null);
//
// if(cursor.moveToFirst()){
// String path = cursor.getString(cursor.getColumnIndex(downloadPath));
// File file = new File(path);
// if(file.exists()){
// file.delete();
// }
// }
// }catch (Exception e){
// Toast.makeText(context, R.string.error_deleting_file, Toast.LENGTH_SHORT).show();
// }
// }
//
//
// db.execSQL("DELETE FROM " + history_table_name + " WHERE id=" + video.getId());
//
// String where = "";
// switch(video.getDownloadedType()){
// case "audio":
// where = " SET downloadedAudio=0 WHERE downloadedAudio=1 AND videoId='" + video.getVideoId()+"'";
// break;
// case "video":
// where = " SET downloadedVideo=0 WHERE downloadedVideo=1 AND videoId='" + video.getVideoId()+"'";
// break;
// }
//
// //remove downloaded status from results
// db.execSQL("UPDATE "+results_table_name+ where);
}
public void clearDeletedHistory(){
// ArrayList<ResultItem> videos = getHistory("","","","");
// for (int i = 0; i < videos.size(); i++){
// ResultItem video = videos.get(i);
// String path = video.getDownloadPath();
// File file = new File(path);
// if(!file.exists() && !path.isEmpty()){
// clearHistoryItem(video, false);
// }
// }
}
public void clearDownloadingHistory(){
// ArrayList<ResultItem> videos = getHistory("","","","");
// for (int i = 0; i < videos.size(); i++){
// ResultItem video = videos.get(i);
// if(video.isQueuedDownload()){
// clearHistoryItem(video, false);
// }
// }
}
public void clearDuplicateHistory(){
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL(
"DELETE FROM " + history_table_name +
" WHERE id > (SELECT MIN(h.id) FROM history h WHERE h.url = " + history_table_name + ".url" +
" AND h.type = " + history_table_name + ".type);"
);
//remove downloaded statuses from results
db.execSQL("UPDATE "+results_table_name+ " SET downloadedAudio=0, downloadedVideo=0" +
" WHERE downloadedAudio=1 OR downloadedVideo=1");
}
public void clearResults(){
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DELETE FROM " + results_table_name);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVer, int newVer) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + results_table_name);
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + history_table_name);
onCreate(sqLiteDatabase);
}
@SuppressLint("Range")
public ArrayList<ResultItem> getResults(){
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + results_table_name, null);
ArrayList<ResultItem> list = new ArrayList<>();
// if(cursor.moveToFirst()){
// do {
// // on below line we are adding the data from cursor to our array list.
// list.add(new ResultItem(cursor.getString(cursor.getColumnIndex(videoId)),
// cursor.getString(cursor.getColumnIndex(url)),
// cursor.getString(cursor.getColumnIndex(title)),
// cursor.getString(cursor.getColumnIndex(author)),
// cursor.getString(cursor.getColumnIndex(duration)),
// cursor.getString(cursor.getColumnIndex(thumb)),
// cursor.getInt(cursor.getColumnIndex(downloadedAudio)),
// cursor.getInt(cursor.getColumnIndex(downloadedVideo)),
// cursor.getInt(cursor.getColumnIndex(isPlaylistItem)),
// cursor.getString(cursor.getColumnIndex(website)),
// cursor.getInt(cursor.getColumnIndex(downloadedAudio)),
// cursor.getInt(cursor.getColumnIndex(downloadingVideo)),
// cursor.getString(cursor.getColumnIndex(playlistTitle))));
// } while (cursor.moveToNext());
// }
//
// cursor.close();
return list;
}
@SuppressLint("Range")
public ArrayList<ResultItem> getHistory(String query, String format, String site, String sort){
SQLiteDatabase db = this.getReadableDatabase();
if (sort == null || sort.isEmpty()) sort = "DESC";
Cursor cursor = db.rawQuery("SELECT * FROM " + history_table_name
+ " WHERE title LIKE '%"+query+"%'"+
" AND type LIKE '%"+format+"%'"+
" AND website LIKE '%"+site+"%'"+
" ORDER BY id "+sort,
null);
ArrayList<ResultItem> list = new ArrayList<>();
//
// if(cursor.moveToFirst()){
// do {
// // on below line we are adding the data from cursor to our array list.
// list.add(new ResultItem(cursor.getInt(cursor.getColumnIndex(id)),
// cursor.getString(cursor.getColumnIndex(url)),
// cursor.getString(cursor.getColumnIndex(title)),
// cursor.getString(cursor.getColumnIndex(author)),
// cursor.getString(cursor.getColumnIndex(duration)),
// cursor.getString(cursor.getColumnIndex(thumb)),
// cursor.getString(cursor.getColumnIndex(type)),
// cursor.getString(cursor.getColumnIndex(time)),
// cursor.getString(cursor.getColumnIndex(downloadPath)),
// cursor.getString(cursor.getColumnIndex(website)),
// cursor.getInt(cursor.getColumnIndex(isQueuedDownload))));
// } while (cursor.moveToNext());
// }
//
// cursor.close();
return list;
}
public void addToResults(ArrayList<ResultItem> videot){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
// for(ResultItem v : videot){
// values.put(videoId, v.getVideoId());
// values.put(url, v.getURL());
// values.put(title, v.getTitle());
// values.put(author, v.getAuthor());
// values.put(duration, v.getDuration());
// values.put(thumb, v.getThumb());
// values.put(downloadedAudio, v.isAudioDownloaded());
// values.put(downloadedVideo, v.isVideoDownloaded());
// values.put(isPlaylistItem, v.getIsPlaylistItem());
// values.put(website, v.getWebsite());
// values.put(downloadingAudio, 0);
// values.put(downloadingVideo, 0);
// values.put(playlistTitle, v.getPlaylistTitle());
//
// db.insert(results_table_name, null, values);
// }
//
// db.close();
}
public void addToHistory(ResultItem v){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
//
// values.put(url, v.getURL());
// values.put(title, v.getTitle());
// values.put(author, v.getAuthor());
// values.put(duration, v.getDuration());
// values.put(thumb, v.getThumb());
// values.put(type, v.getDownloadedType());
// values.put(time, v.getDownloadedTime());
// values.put(downloadPath, v.getDownloadPath());
// values.put(website, v.getWebsite());
// values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0);
//
// db.insert(history_table_name, null, values);
// db.close();
}
public void updateHistoryItem(ResultItem v){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
// values.put(url, v.getURL());
// values.put(title, v.getTitle());
// values.put(author, v.getAuthor());
// values.put(duration, v.getDuration());
// values.put(thumb, v.getThumb());
// values.put(type, v.getDownloadedType());
// values.put(time, v.getDownloadedTime());
// values.put(downloadPath, v.getDownloadPath());
// values.put(website, v.getWebsite());
// values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0);
//
// String where = url + "='"+v.getURL()+"' AND "+isQueuedDownload+"=1 AND "+type+"='"+v.getDownloadedType()+"'";
// db.update(history_table_name, values, where, null);
// db.close();
}
public void updateDownloadStatusOnResult(String id, String type, boolean downloaded){
SQLiteDatabase db = this.getReadableDatabase();
ContentValues values = new ContentValues();
switch (type){
case "audio":
if (downloaded) values.put(downloadedAudio, 1);
values.put(downloadingAudio, 0);
break;
case "video":
if (downloaded) values.put(downloadedVideo, 1);
values.put(downloadingVideo, 0);
break;
}
db.update(results_table_name, values, "videoId = ?", new String[]{id});
}
public void updateDownloadingStatusOnResult(String id, String type, boolean downloading){
SQLiteDatabase db = this.getReadableDatabase();
ContentValues values = new ContentValues();
type = (type.equals("audio")) ? downloadingAudio : downloadingVideo;
int value = (downloading) ? 1 : 0;
values.put(type, value);
db.update(results_table_name, values, "videoId = ?", new String[]{id});
}
@SuppressLint("Range")
public int checkDownloaded(String url, String downloadType){
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + history_table_name + " WHERE url='" +
url + "' AND type='"+downloadType + "' LIMIT 1", null);
if(cursor.moveToFirst()){
String path = cursor.getString(cursor.getColumnIndex(downloadPath));
File file = new File(path);
if(!file.exists() && !path.isEmpty()){
return 0;
}else {
return 1;
}
}
return 0;
}
}

View file

@ -1,74 +0,0 @@
package com.deniscerri.ytdlnis.service;
import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.util.LinkedList;
public class DownloadInfo {
private ResultItem video;
private int progress;
private LinkedList<ResultItem> downloadQueue;
private String outputLine;
private String downloadStatus;
private String downloadPath;
private String downloadType;
public DownloadInfo(){}
public ResultItem getVideo() {
return video;
}
public void setVideo(ResultItem video) {
this.video = video;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
public LinkedList<ResultItem> getDownloadQueue() {
return downloadQueue;
}
public void setDownloadQueue(LinkedList<ResultItem> downloadQueue) {
this.downloadQueue = downloadQueue;
this.video = downloadQueue.peek();
}
public String getOutputLine() {
return outputLine;
}
public void setOutputLine(String outputLine) {
this.outputLine = outputLine;
}
public String getDownloadStatus(){
return downloadStatus;
}
public void setDownloadStatus(String status){
downloadStatus = status;
}
public String getDownloadPath(){
return downloadPath;
}
public void setDownloadPath(String path){
this.downloadPath = path;
}
public String getDownloadType() {
return downloadType;
}
public void setDownloadType(String downloadType) {
this.downloadType = downloadType;
}
}

View file

@ -0,0 +1,19 @@
package com.deniscerri.ytdlnis.service
import com.deniscerri.ytdlnis.database.models.ResultItem
import java.util.*
class DownloadInfo {
var video: ResultItem? = null
var progress = 0
var downloadQueue: LinkedList<ResultItem>? = null
private set
var outputLine: String? = null
var downloadStatus: String? = null
var downloadPath: String? = null
var downloadType: String? = null
fun setDownloadQueue(downloadQueue: LinkedList<ResultItem>) {
this.downloadQueue = downloadQueue
video = downloadQueue.peek()
}
}

View file

@ -1,11 +0,0 @@
package com.deniscerri.ytdlnis.service;
public interface IDownloaderListener {
void onDownloadStart(DownloadInfo downloadInfo);
void onDownloadProgress(DownloadInfo downloadInfo);
void onDownloadError(DownloadInfo downloadInfo);
void onDownloadEnd(DownloadInfo downloadInfo);
void onDownloadCancel(DownloadInfo downloadInfo);
void onDownloadCancelAll(DownloadInfo downloadInfo);
void onDownloadServiceEnd();
}

View file

@ -0,0 +1,11 @@
package com.deniscerri.ytdlnis.service
interface IDownloaderListener {
fun onDownloadStart(downloadInfo: DownloadInfo?)
fun onDownloadProgress(downloadInfo: DownloadInfo?)
fun onDownloadError(downloadInfo: DownloadInfo?)
fun onDownloadEnd(downloadInfo: DownloadInfo?)
fun onDownloadCancel(downloadInfo: DownloadInfo?)
fun onDownloadCancelAll(downloadInfo: DownloadInfo?)
fun onDownloadServiceEnd()
}

View file

@ -1,16 +0,0 @@
package com.deniscerri.ytdlnis.service;
import android.app.Activity;
import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.util.ArrayList;
public interface IDownloaderService {
DownloadInfo getInfo();
void addActivity(Activity activity, ArrayList<IDownloaderListener> callback);
void removeActivity(Activity activity);
void updateQueue(ArrayList<ResultItem> queue);
void cancelDownload(boolean cancelAll);
void removeItemFromDownloadQueue(ResultItem video, String type);
}

View file

@ -0,0 +1,13 @@
package com.deniscerri.ytdlnis.service
import android.app.Activity
import com.deniscerri.ytdlnis.database.models.ResultItem
interface IDownloaderService {
val info: DownloadInfo?
fun addActivity(activity: Activity?, callback: ArrayList<IDownloaderListener?>?)
fun removeActivity(activity: Activity?)
fun updateQueue(queue: ArrayList<ResultItem?>?)
fun cancelDownload(cancelAll: Boolean)
fun removeItemFromDownloadQueue(video: ResultItem?, type: String?)
}

View file

@ -1,47 +0,0 @@
package com.deniscerri.ytdlnis.service.api
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import retrofit2.Call
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
interface InvidiousService {
@GET("video/{id}")
suspend fun getVideo(
@Path("id") id : String
) : Call<ResultItem>
@GET("playlist/{id}")
suspend fun getPlaylist(
@Path("id") id: String
) : Response<JsonObject>
@GET("trending?type=music&region={regionCode}")
suspend fun getTrending(
@Path("regionCode") regionCode: String
) : Response<JsonArray>
@GET("search/suggestions?q={query}")
suspend fun getSearchSuggestions(
@Path("query") query: String
) : Response<JsonObject>
companion object {
var invidiousService : InvidiousService? = null
fun getInstance() : InvidiousService {
return invidiousService ?: run {
val retrofit = Retrofit.Builder()
.baseUrl("https://invidious.baczek.me/api/v1/")
.addConverterFactory(GsonConverterFactory.create())
.build()
invidiousService = retrofit.create(InvidiousService::class.java)
invidiousService!!
}
}
}
}

View file

@ -1,66 +0,0 @@
package com.deniscerri.ytdlnis.service.api
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
interface YoutubeAPIService {
@GET("videos?part=snippet,contentDetails&id={id}&key={apiKey}")
suspend fun getVideo(
@Path("id") id: String?
) : Response<JsonObject>
@GET("playlistItems?part=snippet&pageToken={nextPageToken}&maxResults=50&regionCode={regionCode}&playlistId={playlistId}&key={apiKey}")
suspend fun getPlaylist(
@Path("nextPageToken") nextPageToken: String,
@Path("playlistId") playlistId : String,
@Path("apiKey") apiKey : String
) : Response<JsonObject>
@GET("videos?part=snippet&chart=mostPopular&videoCategoryId=10&regionCode={regionCode}&maxResults=25&key={apiKey}")
suspend fun getTrending(
@Path("regionCode") regionCode: String,
@Path("apiKey") apiKey : String
) : Response<JsonArray>
@GET("videos?part=contentDetails&chart=mostPopular&videoCategoryId=10&regionCode={regionCode}&maxResults=25&key={apiKey}")
suspend fun getTrendingExtra(
@Path("regionCode") regionCode: String,
@Path("apiKey") apiKey : String
) : Response<JsonArray>
@GET("search?part=snippet&q={query}&maxResults=25&regionCode={regionCode}&key={apiKey}")
suspend fun search(
@Path("query") query: String,
@Path("regionCode") regionCode: String,
@Path("apiKey") apiKey: String
) : Response<JsonObject>
@GET("videos?id={ids}&part=contentDetails&regionCode={regionCode}&key={apiKey}")
suspend fun getExtraData(
@Path("ids") ids: String,
@Path("regionCode") regionCode: String,
@Path("apiKey") apiKey: String
) : Response<JsonObject>
companion object {
var invidiousService : YoutubeAPIService? = null
lateinit var apiKey : String
lateinit var regionCode: String
fun getInstance(key: String, regionCode: String) : YoutubeAPIService {
apiKey = key
return invidiousService ?: run {
val retrofit = Retrofit.Builder()
.baseUrl("https://www.googleapis.com/youtube/v3/")
.addConverterFactory(GsonConverterFactory.create())
.build()
invidiousService = retrofit.create(YoutubeAPIService::class.java)
invidiousService!!
}
}
}
}

View file

@ -1,213 +0,0 @@
package com.deniscerri.ytdlnis.ui;
import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.DownloaderService;
import com.deniscerri.ytdlnis.service.DownloadInfo;
import com.deniscerri.ytdlnis.service.IDownloaderListener;
import com.deniscerri.ytdlnis.service.IDownloaderService;
import com.deniscerri.ytdlnis.util.NotificationUtil;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
import java.util.ArrayList;
public class CustomCommandActivity extends AppCompatActivity {
private static final String TAG = "CustomCommandActivity";
private MaterialToolbar topAppBar;
private boolean isDownloadServiceRunning = false;
public DownloaderService downloaderService;
private TextView output;
private EditText input;
private ExtendedFloatingActionButton fab;
private ExtendedFloatingActionButton cancelFab;
private IDownloaderService iDownloaderService;
private ScrollView scrollView;
Context context;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
downloaderService = ((DownloaderService.LocalBinder) service).getService();
iDownloaderService = (IDownloaderService) service;
isDownloadServiceRunning = true;
try{
ArrayList<IDownloaderListener> listeners = new ArrayList<>();
listeners.add(listener);
iDownloaderService.addActivity(CustomCommandActivity.this, listeners);
listener.onDownloadStart(iDownloaderService.getInfo());
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
downloaderService = null;
iDownloaderService = null;
isDownloadServiceRunning = false;
}
};
public IDownloaderListener listener = new IDownloaderListener() {
public void onDownloadStart(DownloadInfo info) {
input.setEnabled(false);
output.setText("");
swapFabs();
}
public void onDownloadProgress(DownloadInfo info) {
String newInfo = info.getOutputLine();
if (newInfo.contains("[download]")){
String temp = output.getText().toString();
output.setText(
temp.substring(0, temp.lastIndexOf(System.getProperty("line.separator")) - 2)
);
}
output.append(info.getOutputLine() + " \n");
output.scrollTo(0, output.getHeight());
scrollView.fullScroll(View.FOCUS_DOWN);
}
public void onDownloadError(DownloadInfo info) {
output.append("\n" + info.getOutputLine());
scrollView.scrollTo(0, scrollView.getMaxScrollAmount());
input.setText("yt-dlp ");
input.setEnabled(true);
swapFabs();
}
public void onDownloadEnd(DownloadInfo info) {
output.append(info.getOutputLine());
scrollView.scrollTo(0, scrollView.getMaxScrollAmount());
// MEDIA SCAN
MediaScannerConnection.scanFile(context, new String[]{"/storage"}, null, null);
input.setText("yt-dlp ");
input.setEnabled(true);
swapFabs();
}
@Override
public void onDownloadCancel(DownloadInfo downloadInfo) {}
@Override
public void onDownloadCancelAll(DownloadInfo downloadInfo){}
public void onDownloadServiceEnd() {
stopDownloadService();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_command);
context = getBaseContext();
scrollView = findViewById(R.id.custom_command_scrollview);
topAppBar = findViewById(R.id.custom_command_toolbar);
topAppBar.setNavigationOnClickListener(view -> onBackPressed());
output = findViewById(R.id.custom_command_output);
output.setTextIsSelectable(true);
input = findViewById(R.id.command_edittext);
input.requestFocus();
fab = findViewById(R.id.command_fab);
fab.setOnClickListener(view -> {
if (isStoragePermissionGranted()){
startDownloadService(input.getText().toString(), NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID);
}
});
cancelFab = findViewById(R.id.cancel_command_fab);
cancelFab.setOnClickListener(view -> {
cancelDownloadService();
swapFabs();
input.setEnabled(true);
});
handleIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent){
String action = intent.getAction();
String type = intent.getType();
Log.e(TAG, action + " " + type);
if (action.equals(Intent.ACTION_SEND) && type != null) {
Log.e(TAG, action);
String txt = "yt-dlp " + intent.getStringExtra(Intent.EXTRA_TEXT);
input.setText(txt);
}
}
private void swapFabs(){
int cancel = cancelFab.getVisibility();
int start = fab.getVisibility();
cancelFab.setVisibility(start);
fab.setVisibility(cancel);
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
public void startDownloadService(String command, int id){
if(isDownloadServiceRunning) return;
Intent serviceIntent = new Intent(context, DownloaderService.class);
serviceIntent.putExtra("command", command);
serviceIntent.putExtra("id", id);
context.getApplicationContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public void stopDownloadService(){
if(!isDownloadServiceRunning) return;
iDownloaderService.removeActivity(this);
context.getApplicationContext().unbindService(serviceConnection);
downloaderService.stopForeground(true);
downloaderService.stopSelf();
isDownloadServiceRunning = false;
}
public void cancelDownloadService(){
if(!isDownloadServiceRunning) return;
iDownloaderService.cancelDownload(false);
stopDownloadService();
}
public boolean isStoragePermissionGranted() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
return true;
}else{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
}

View file

@ -0,0 +1,212 @@
package com.deniscerri.ytdlnis.ui
import android.Manifest
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.media.MediaScannerConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.View
import android.widget.EditText
import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.deniscerri.ytdlnis.DownloaderService
import com.deniscerri.ytdlnis.DownloaderService.LocalBinder
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.service.DownloadInfo
import com.deniscerri.ytdlnis.service.IDownloaderListener
import com.deniscerri.ytdlnis.service.IDownloaderService
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
class CustomCommandActivity : AppCompatActivity() {
private var topAppBar: MaterialToolbar? = null
private var isDownloadServiceRunning = false
var downloaderService: DownloaderService? = null
private var output: TextView? = null
private var input: EditText? = null
private var fab: ExtendedFloatingActionButton? = null
private var cancelFab: ExtendedFloatingActionButton? = null
private var iDownloaderService: IDownloaderService? = null
private var scrollView: ScrollView? = null
var context: Context? = null
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
downloaderService = (service as LocalBinder).service
iDownloaderService = service
isDownloadServiceRunning = true
try {
val listeners = ArrayList<IDownloaderListener>()
listeners.add(listener)
iDownloaderService!!.addActivity(this@CustomCommandActivity, listeners)
listener.onDownloadStart(iDownloaderService!!.info)
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onServiceDisconnected(componentName: ComponentName) {
downloaderService = null
iDownloaderService = null
isDownloadServiceRunning = false
}
}
var listener: IDownloaderListener = object : IDownloaderListener {
override fun onDownloadStart(info: DownloadInfo) {
input!!.isEnabled = false
output!!.text = ""
swapFabs()
}
override fun onDownloadProgress(info: DownloadInfo) {
val newInfo = info.outputLine
if (newInfo.contains("[download]")) {
val temp = output!!.text.toString()
output!!.text =
temp.substring(0, temp.lastIndexOf(System.getProperty("line.separator")!!) - 2)
}
output!!.append(
"""${info.outputLine}
"""
)
output!!.scrollTo(0, output!!.height)
scrollView!!.fullScroll(View.FOCUS_DOWN)
}
@SuppressLint("SetTextI18n")
override fun onDownloadError(info: DownloadInfo) {
output!!.append(
"""
${info.outputLine}
""".trimIndent()
)
scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount)
input!!.setText("yt-dlp ")
input!!.isEnabled = true
swapFabs()
}
@SuppressLint("SetTextI18n")
override fun onDownloadEnd(info: DownloadInfo) {
output!!.append(info.outputLine)
scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount)
// MEDIA SCAN
MediaScannerConnection.scanFile(context, arrayOf("/storage"), null, null)
input!!.setText("yt-dlp ")
input!!.isEnabled = true
swapFabs()
}
override fun onDownloadCancel(downloadInfo: DownloadInfo) {}
override fun onDownloadCancelAll(downloadInfo: DownloadInfo) {}
override fun onDownloadServiceEnd() {
stopDownloadService()
}
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom_command)
context = baseContext
scrollView = findViewById(R.id.custom_command_scrollview)
topAppBar = findViewById(R.id.custom_command_toolbar)
topAppBar!!.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
output = findViewById(R.id.custom_command_output)
output!!.setTextIsSelectable(true)
input = findViewById(R.id.command_edittext)
input!!.requestFocus()
fab = findViewById(R.id.command_fab)
fab!!.setOnClickListener {
if (isStoragePermissionGranted) {
startDownloadService(
input!!.text.toString(),
NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID
)
}
}
cancelFab = findViewById(R.id.cancel_command_fab)
cancelFab!!.setOnClickListener {
cancelDownloadService()
swapFabs()
input!!.isEnabled = true
}
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")
if (action == Intent.ACTION_SEND && type != null) {
Log.e(TAG, action)
val txt = "yt-dlp " + intent.getStringExtra(Intent.EXTRA_TEXT)
input!!.setText(txt)
}
}
private fun swapFabs() {
val cancel = cancelFab!!.visibility
val start = fab!!.visibility
cancelFab!!.visibility = start
fab!!.visibility = cancel
}
private fun startDownloadService(command: String?, id: Int) {
if (isDownloadServiceRunning) return
val serviceIntent = Intent(context, DownloaderService::class.java)
serviceIntent.putExtra("command", command)
serviceIntent.putExtra("id", id)
context!!.applicationContext.bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE)
}
fun stopDownloadService() {
if (!isDownloadServiceRunning) return
iDownloaderService!!.removeActivity(this)
context!!.applicationContext.unbindService(serviceConnection)
downloaderService!!.stopForeground(true)
downloaderService!!.stopSelf()
isDownloadServiceRunning = false
}
fun cancelDownloadService() {
if (!isDownloadServiceRunning) return
iDownloaderService!!.cancelDownload(false)
stopDownloadService()
}
private val isStoragePermissionGranted: Boolean
get() = if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
== PackageManager.PERMISSION_GRANTED
) {
true
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1
)
false
}
companion object {
private const val TAG = "CustomCommandActivity"
}
}

View file

@ -20,7 +20,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.HistoryAdapter
import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
@ -45,7 +44,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
private var downloading = false
private var fragmentView: View? = null
private var databaseManager: DatabaseManager? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private var fragmentContext: Context? = null
@ -165,7 +163,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
val searchView = topAppBar!!.menu.findItem(R.id.search_downloads).actionView as SearchView?
searchView!!.inputType = InputType.TYPE_CLASS_TEXT
searchView.queryHint = getString(R.string.search_history_hint)
databaseManager = DatabaseManager(context)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
topAppBar!!.menu.findItem(R.id.search_downloads).collapseActionView()

View file

@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -23,7 +22,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.HomeAdapter
import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
@ -37,18 +35,13 @@ import com.deniscerri.ytdlnis.util.InfoUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.ChipGroup
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import java.text.DecimalFormat
import java.util.*
import kotlin.math.log10
import kotlin.math.pow
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener {
private var progressBar: LinearProgressIndicator? = null
@ -70,7 +63,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
private var downloading = false
private var fragmentView: View? = null
private var databaseManager: DatabaseManager? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private var fragmentContext: Context? = null
@ -239,7 +231,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
val searchView = topAppBar!!.menu.findItem(R.id.search).actionView as SearchView?
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_URI
searchView.queryHint = getString(R.string.search_hint)
databaseManager = DatabaseManager(context)
infoUtil = InfoUtil(requireContext())
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
@ -390,7 +381,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
downloadItem.id = it
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
bottomSheet.show(parentFragmentManager, "bottomSheet")
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
}
}

View file

@ -1,13 +0,0 @@
package com.deniscerri.ytdlnis.ui;
import android.os.Bundle;
import androidx.preference.PreferenceFragmentCompat;
import com.deniscerri.ytdlnis.R;
public class MoreFragment extends PreferenceFragmentCompat {
public static final String TAG = "MoreFragment";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.more_preferences, rootKey);
}
}

View file

@ -0,0 +1,15 @@
package com.deniscerri.ytdlnis.ui
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import com.deniscerri.ytdlnis.R
class MoreFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.more_preferences, rootKey)
}
companion object {
const val TAG = "MoreFragment"
}
}

View file

@ -6,6 +6,7 @@ import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment
import androidx.lifecycle.ViewModelProvider
@ -13,6 +14,8 @@ import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
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.tabs.TabLayout
@ -28,11 +31,18 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val behavior = BottomSheetBehavior.from(view.parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.download_bottom_sheet, null)
dialog.setContentView(view)
//view.minimumHeight = resources.displayMetrics.heightPixels
tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager)
@ -79,7 +89,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("bottomSheet")!!).commit()
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadSingleSheet")!!).commit()
for (i in 0 until viewPager2.adapter?.itemCount!!){
if (parentFragmentManager.findFragmentByTag("f${i}") != null){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()

View file

@ -1,38 +0,0 @@
package com.deniscerri.ytdlnis.ui.settings;
import android.content.Context;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import com.deniscerri.ytdlnis.R;
import com.google.android.material.appbar.MaterialToolbar;
public class SettingsActivity extends AppCompatActivity{
private FragmentManager fm;
private MaterialToolbar topAppBar;
Context context;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
context = getBaseContext();
topAppBar = findViewById(R.id.settings_toolbar);
topAppBar.setNavigationOnClickListener(view -> onBackPressed());
fm = getSupportFragmentManager();
fm.beginTransaction()
.replace(R.id.settings_frame_layout, new SettingsFragment())
.commit();
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
}

View file

@ -0,0 +1,26 @@
package com.deniscerri.ytdlnis.ui.settings
import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager
import com.deniscerri.ytdlnis.R
import com.google.android.material.appbar.MaterialToolbar
class SettingsActivity : AppCompatActivity() {
private var fm: FragmentManager? = null
private var topAppBar: MaterialToolbar? = null
var context: Context? = null
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
context = baseContext
topAppBar = findViewById(R.id.settings_toolbar)
topAppBar!!.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
fm = supportFragmentManager
fm!!.beginTransaction()
.replace(R.id.settings_frame_layout, SettingsFragment())
.commit()
}
}

View file

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context
import android.util.Log
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.ResultItemWithFormats
@ -26,14 +25,12 @@ class InfoUtil(context: Context) {
private var items: ArrayList<ResultItemWithFormats?>
private var key: String? = null
private var useInvidous = false
private var databaseManager: DatabaseManager? = null
init {
try {
val sharedPreferences =
context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
key = sharedPreferences.getString("api_key", "")
databaseManager = DatabaseManager(context)
} catch (e: Exception) {
e.printStackTrace()
}
@ -258,9 +255,6 @@ class InfoUtil(context: Context) {
val duration = obj.getString("duration")
val thumb = obj.getString("thumb")
val url = "https://www.youtube.com/watch?v=$id"
val downloadedAudio = databaseManager!!.checkDownloaded(url, "audio")
val downloadedVideo = databaseManager!!.checkDownloaded(url, "video")
val isPlaylist = 0
video = ResultItemWithFormats(
ResultItem(0,
url,

View file

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#00A6FF"
<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:color/white" android:pathData="M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H15v-8h5V8L14,2zM13,9V3.5L18.5,9H13zM17,21.66V16h5.66v2h-2.24l2.95,2.95l-1.41,1.41L19,19.41l0,2.24H17z"/>
<path android:fillColor="?android:colorAccent" android:pathData="M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H15v-8h5V8L14,2zM13,9V3.5L18.5,9H13zM17,21.66V16h5.66v2h-2.24l2.95,2.95l-1.41,1.41L19,19.41l0,2.24H17z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?android:textColorPrimary" android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19L3,19L3,5h18v14zM8,15c0,-1.66 1.34,-3 3,-3 0.35,0 0.69,0.07 1,0.18L12,6h5v2h-3v7.03c-0.02,1.64 -1.35,2.97 -3,2.97 -1.66,0 -3,-1.34 -3,-3z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?android:textColorPrimary" android:pathData="M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM11,15L9.5,15v-2h-2v2L6,15L6,9h1.5v2.5h2L9.5,9L11,9v6zM13,9h4c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h-4L13,9zM14.5,13.5h2v-3h-2v3z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,9H4v2h16V9zM4,15h16v-2H4V15z"/>
</vector>

View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/downloads_card_constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.google.android.material.button.MaterialButton
android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="end"
android:padding="0dp"
app:icon="@drawable/ic_handle" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/download_card_view"
android:layout_width="match_parent"
android:layout_height="95dp"
android:layout_margin="10dp"
android:checkable="true"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:cardMaxElevation="12dp"
app:cardPreventCornerOverlap="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/materialButton"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/downloads_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/download_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:alpha="0.7"
android:indeterminate="true"
android:scaleY="100"
android:visibility="gone" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="296dp"
android:layout_height="41dp"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/author"
android:layout_width="296dp"
android:layout_height="23dp"
android:gravity="bottom"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingBottom="5dp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="1.5"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<TextView
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/author"
app:layout_constraintVertical_bias="1.0" />
<TextView
android:id="@+id/encoding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/container" />
<TextView
android:id="@+id/filesize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/encoding" />
<com.google.android.material.button.MaterialButton
android:id="@+id/downloads_download_button_type"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_margin="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>

View file

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configure_download"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="end"
app:icon="@drawable/ic_format"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/materialButton2"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/materialButton2"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="end"
app:icon="@drawable/ic_download_type"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/download_multiple_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="10dp"
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:id="@+id/bottomsheet_schedule_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_clock" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:gravity="end"
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:id="@+id/bottomsheet_cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_cancel" />
<Button
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:id="@+id/bottomsheet_download_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download"
app:icon="@drawable/ic_down"
android:autoLink="all"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -166,4 +166,5 @@
<string name="container">Container</string>
<string name="template">Template</string>
<string name="history">History</string>
<string name="logs">Logs</string>
</resources>

View file

@ -1,6 +1,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:enabled="false"
android:layout="@layout/fragment_more"/>
@ -9,6 +10,7 @@
app:icon="@drawable/ic_code"
app:key="rreth"
app:summary="https://github.com/deniscerri/ytdlnis"
app:allowDividerBelow="true"
app:title="@string/source_code">
<intent
android:action="android.intent.action.VIEW"
@ -17,13 +19,19 @@
<Preference
app:icon="@drawable/ic_baseline_keyboard_arrow_right_24"
app:allowDividerAbove="true"
app:allowDividerBelow="true"
app:key="run_command"
app:title="@string/custom_command">
<intent android:action="ytdlnis.page.CustomCommandActivity" />
</Preference>
<Preference
app:icon="@drawable/ic_baseline_file_open_24"
app:key="download_logs"
app:allowDividerBelow="true"
app:title="@string/logs">
<intent android:action="ytdlnis.page.DownloadLogsActivity" />
</Preference>
<Preference
app:icon="@drawable/ic_settings"
app:key="open_settings"
@ -32,4 +40,5 @@
</Preference>
</PreferenceScreen>