diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
index 12ee8e76..ddd7d6b8 100644
--- a/.idea/assetWizardSettings.xml
+++ b/.idea/assetWizardSettings.xml
@@ -320,7 +320,7 @@
-
+
@@ -331,7 +331,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 155a8652..7f3baebb 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -40,6 +40,7 @@
+
@@ -83,7 +84,7 @@
-
+
@@ -91,7 +92,7 @@
-
+
@@ -120,6 +121,7 @@
+
diff --git a/README.md b/README.md
index 06bb51d8..6e34543b 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,24 @@
+## Create a YouTube API Key
+
+Using your personal api key will increase youtube result speed inside the app drastically. On top of that, the app will show you trending videos on youtube every time you open the app.
+Here is how to do it:
+
+- Go to [Google Console](https://console.cloud.google.com/projectselector2/apis/dashboard)
+- Accept Terms & Services and click Create Project
+- Click "Enabled API's and Services"
+- Search for "Youtube Data API V3" click and enable it
+- Click the Credentials tab on the left
+- Click "Create Credentials" and choose API Key
+
+Copy the key that appears and paste it in this app's settings.
+
+## Connect with YouTube Revanced
+
+The App's package name is com.deniscerri.ytdl
+
## License
[GNU GPL v3.0](https://github.com/deniscerri/ytdlnis/blob/main/LICENSE)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3b56dea1..0f45df91 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -50,6 +50,16 @@
android:enabled="true"
android:exported="false" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadsRecyclerViewAdapter.java b/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadsRecyclerViewAdapter.java
index 1784f67d..d283997c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadsRecyclerViewAdapter.java
+++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadsRecyclerViewAdapter.java
@@ -24,6 +24,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.database.Video;
import com.google.android.material.button.MaterialButton;
+import com.google.android.material.card.MaterialCardView;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.squareup.picasso.Picasso;
@@ -32,6 +33,7 @@ import java.util.ArrayList;
public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter {
private ArrayList videoList;
+ private ArrayList checkedVideos;
private ArrayList websites;
private final OnItemClickListener onItemClickListener;
private Activity activity;
@@ -39,6 +41,7 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter videos, OnItemClickListener onItemClickListener, Activity activity){
this.videoList = videos;
this.websites = new ArrayList<>();
+ this.checkedVideos = new ArrayList<>();
this.onItemClickListener = onItemClickListener;
this.activity = activity;
}
@@ -49,7 +52,7 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter onItemClickListener.onButtonClick(position));
@@ -117,7 +122,6 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter onItemClickListener.onCardClick(position));
+ if(checkedVideos.contains(position)){
+ card.setChecked(true);
+ card.setStrokeWidth(5);
+ }else{
+ card.setChecked(false);
+ card.setStrokeWidth(0);
+ }
+
+ boolean finalFilePresent = filePresent;
+ card.setOnLongClickListener(view -> {
+ checkCard(card, position);
+ return true;
+ });
+ card.setOnClickListener(view -> {
+ if(checkedVideos.size() > 0){
+ checkCard(card, position);
+ }else{
+ onItemClickListener.onCardClick(position, finalFilePresent);
+ }
+ });
+ }
+
+ private void checkCard(MaterialCardView card, int position){
+ if(card.isChecked()){
+ card.setStrokeWidth(0);
+ checkedVideos.remove(Integer.valueOf(position));
+ }else{
+ card.setStrokeWidth(5);
+ checkedVideos.add(position);
+ }
+ card.setChecked(!card.isChecked());
+ onItemClickListener.onCardSelect(position, card.isChecked());
}
@Override
@@ -147,7 +182,8 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter downloadsObjects;
+ public ArrayList selectedObjects;
private LinearProgressIndicator progressBar;
+ private ExtendedFloatingActionButton deleteFab;
private String format = "";
private String website = "";
private String sort = "DESC";
@@ -252,8 +256,14 @@ public class DownloadsFragment extends Fragment implements DownloadsRecyclerView
no_results = fragmentView.findViewById(R.id.downloads_no_results);
selectionChips = fragmentView.findViewById(R.id.downloads_selection_chips);
websiteGroup = fragmentView.findViewById(R.id.website_chip_group);
+ deleteFab = fragmentView.findViewById(R.id.delete_selected_fab);
+
+ deleteFab.setTag("deleteSelected");
+ deleteFab.setOnClickListener(this);
+
uiHandler = new Handler(Looper.getMainLooper());
downloadsObjects = new ArrayList<>();
+ selectedObjects = new ArrayList<>();
downloading = mainActivity.isDownloadServiceRunning();
recyclerView = fragmentView.findViewById(R.id.recycler_view_downloads);
@@ -557,15 +567,65 @@ public class DownloadsFragment extends Fragment implements DownloadsRecyclerView
if(id == R.id.bottomsheet_remove_button){
removedownloadsItem((Integer) v.getTag());
}else if(id == R.id.bottom_sheet_link){
- copyLinkToClipBoard((Integer) v.getTag());
- }else if(id == R.id.bottomsheet_open_link_button){
openLinkIntent((Integer) v.getTag());
+ }else if(id == R.id.bottomsheet_open_file_button){
+ openFileIntent((Integer) v.getTag());
+ }else if (id == R.id.delete_selected_fab){
+ removeSelectedItems();
}
}
+ @Override
+ public boolean onLongClick(View v) {
+ int id = v.getId();
+ if(id == R.id.bottom_sheet_link){
+ copyLinkToClipBoard((Integer) v.getTag());
+ return true;
+ }
+ return false;
+ }
+
+ private void removeSelectedItems(){
+ if(bottomSheet != null) bottomSheet.hide();
+ final boolean[] delete_file = {false};
+ dbManager = new DBManager(context);
+
+ MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
+ delete_dialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items));
+ delete_dialog.setMultiChoiceItems(new String[]{getString(R.string.delete_files_too)}, new boolean[]{false}, (dialogInterface, i, b) -> delete_file[0] = b);
+ delete_dialog.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
+ dialogInterface.cancel();
+ });
+ delete_dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
+ for (int j = 0; j < selectedObjects.size(); j++){
+ Video v = selectedObjects.get(j);
+ int position = downloadsObjects.indexOf(v);
+ downloadsObjects.remove(v);
+ downloadsRecyclerViewAdapter.notifyItemRemoved(position);
+ downloadsRecyclerViewAdapter.setVideoList(downloadsObjects);
+ dbManager.clearHistoryItem(v, delete_file[0]);
+ }
+ updateWebsiteChips();
+ dbManager.close();
+ selectedObjects = new ArrayList<>();
+ downloadsRecyclerViewAdapter.clearCheckedVideos();
+ deleteFab.setVisibility(View.GONE);
+
+ if(downloadsObjects.size() == 0){
+ uiHandler.post(() -> {
+ no_results.setVisibility(View.VISIBLE);
+ selectionChips.setVisibility(View.GONE);
+ websiteGroup.removeAllViews();
+ });
+ }
+ });
+ delete_dialog.show();
+ }
+
private void removedownloadsItem(int position){
if(bottomSheet != null) bottomSheet.hide();
final boolean[] delete_file = {false};
+ dbManager = new DBManager(context);
Video v = downloadsObjects.get(position);
MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
@@ -578,9 +638,9 @@ public class DownloadsFragment extends Fragment implements DownloadsRecyclerView
downloadsObjects.remove(position);
downloadsRecyclerViewAdapter.notifyItemRemoved(position);
downloadsRecyclerViewAdapter.setVideoList(downloadsObjects);
- downloadsRecyclerViewAdapter.setWebsiteList();
updateWebsiteChips();
dbManager.clearHistoryItem(v, delete_file[0]);
+ dbManager.close();
if(downloadsObjects.size() == 0){
uiHandler.post(() -> {
@@ -610,8 +670,22 @@ public class DownloadsFragment extends Fragment implements DownloadsRecyclerView
startActivity(i);
}
+ private void openFileIntent(int position){
+ String downloadPath =downloadsObjects.get(position).getDownloadPath();
+ File file = new File(downloadPath);
+
+ Uri uri = FileProvider.getUriForFile(fragmentContext, fragmentContext.getPackageName() + ".fileprovider", file);
+ String mime = mainActivity.getContentResolver().getType(uri);
+
+ Intent i = new Intent(Intent.ACTION_VIEW);
+ i.setDataAndType(uri, mime);
+ i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if(bottomSheet != null) bottomSheet.hide();
+ startActivity(i);
+ }
+
@Override
- public void onCardClick(int position) {
+ public void onCardClick(int position, boolean isFilePresent) {
bottomSheet = new BottomSheetDialog(fragmentContext);
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE);
bottomSheet.setContentView(R.layout.downloads_bottom_sheet);
@@ -628,19 +702,32 @@ public class DownloadsFragment extends Fragment implements DownloadsRecyclerView
link.setText(url);
link.setTag(position);
link.setOnClickListener(this);
+ link.setOnLongClickListener(this);
Button remove = bottomSheet.findViewById(R.id.bottomsheet_remove_button);
remove.setTag(position);
remove.setOnClickListener(this);
- Button openLink = bottomSheet.findViewById(R.id.bottomsheet_open_link_button);
- openLink.setTag(position);
- openLink.setOnClickListener(this);
+ Button openFile = bottomSheet.findViewById(R.id.bottomsheet_open_file_button);
+ openFile.setTag(position);
+ openFile.setOnClickListener(this);
+ if (!isFilePresent) openFile.setVisibility(View.GONE);
bottomSheet.show();
bottomSheet.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
}
+ @Override
+ public void onCardSelect(int position, boolean add) {
+ Video video = downloadsObjects.get(position);
+ if (add) selectedObjects.add(video); else selectedObjects.remove(video);
+ if(selectedObjects.size() > 1){
+ deleteFab.setVisibility(View.VISIBLE);
+ } else {
+ deleteFab.setVisibility(View.GONE);
+ }
+ }
+
@Override
public void onButtonClick(int position) {
Video vid = downloadsObjects.get(position);
diff --git a/app/src/main/res/drawable/ic_baseline_file_open_24.xml b/app/src/main/res/drawable/ic_baseline_file_open_24.xml
new file mode 100644
index 00000000..40c228e8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_file_open_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/downloads_bottom_sheet.xml b/app/src/main/res/layout/downloads_bottom_sheet.xml
index 930e8c02..70c65747 100644
--- a/app/src/main/res/layout/downloads_bottom_sheet.xml
+++ b/app/src/main/res/layout/downloads_bottom_sheet.xml
@@ -50,8 +50,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
- android:gravity="right"
- android:layout_margin="20dp"
+ android:gravity="end"
+ android:layout_margin="10dp"
android:orientation="horizontal">
+ android:text="@string/Open_File"
+ app:icon="@drawable/ic_baseline_file_open_24"
+ />
diff --git a/app/src/main/res/layout/downloads_card.xml b/app/src/main/res/layout/downloads_card.xml
index 32add691..7a1e4d6c 100644
--- a/app/src/main/res/layout/downloads_card.xml
+++ b/app/src/main/res/layout/downloads_card.xml
@@ -14,7 +14,8 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
-
@@ -111,10 +114,9 @@
android:layout_marginStart="10dp"
/>
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_downloads.xml b/app/src/main/res/layout/fragment_downloads.xml
index 85130f6f..3783a4c5 100644
--- a/app/src/main/res/layout/fragment_downloads.xml
+++ b/app/src/main/res/layout/fragment_downloads.xml
@@ -100,37 +100,19 @@
-
-
-
-
+ android:scrollbars="vertical"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
-
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-sq-rAL/strings.xml b/app/src/main/res/values-sq-rAL/strings.xml
index 0c02409e..4fa29aac 100644
--- a/app/src/main/res/values-sq-rAL/strings.xml
+++ b/app/src/main/res/values-sq-rAL/strings.xml
@@ -123,4 +123,10 @@
Vendos Kapituj
Shfaq kartën e shkarkimit
Konfiguro videon përpara se sa ta shkarkosh
+ Disa Tituj
+ Disa Autorë
+ Hap Skedarin
+ Fshi të zgjedhurat
+ Je duke fshirë disa elementë
+ Fshi skedarët nga sistemi
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bf932066..9d2a6e99 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -130,4 +130,8 @@
Configure the item before downloading it
Multiple Titles
Multiple Authors
+ Open File
+ Delete Selected
+ You are going to delete multiple items
+ Delete the files from the system
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 00000000..e541afd3
--- /dev/null
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file