implemented diffutil on history recyclerview

This commit is contained in:
Denis Çerri 2023-01-15 16:48:51 +01:00
parent d91b6dc217
commit 542121d446
No known key found for this signature in database
GPG key ID: 96B3554AF5B193EE
13 changed files with 440 additions and 684 deletions

View file

@ -320,7 +320,7 @@
<PersistentState> <PersistentState>
<option name="values"> <option name="values">
<map> <map>
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/attach_money/baseline_attach_money_24.xml" /> <entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/download/baseline_download_24.xml" />
</map> </map>
</option> </option>
</PersistentState> </PersistentState>
@ -331,7 +331,7 @@
<option name="values"> <option name="values">
<map> <map>
<entry key="color" value="00a6ff" /> <entry key="color" value="00a6ff" />
<entry key="outputName" value="ic_money" /> <entry key="outputName" value="ic_downloads" />
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" /> <entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
</map> </map>
</option> </option>

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "12ee531d801d7e6e3fd888f4907adc81", "identityHash": "1709c1d446102722d4dc7f2cb96cd40e",
"entities": [ "entities": [
{ {
"tableName": "results", "tableName": "results",
@ -68,7 +68,7 @@
}, },
{ {
"tableName": "history", "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` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL)", "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)",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -115,7 +115,7 @@
{ {
"fieldPath": "time", "fieldPath": "time",
"columnName": "time", "columnName": "time",
"affinity": "TEXT", "affinity": "INTEGER",
"notNull": true "notNull": true
}, },
{ {
@ -142,7 +142,7 @@
}, },
{ {
"tableName": "downloads", "tableName": "downloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL)", "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, `formatId` INTEGER NOT NULL, `formatDesc` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL)",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -181,8 +181,14 @@
"notNull": true "notNull": true
}, },
{ {
"fieldPath": "type", "fieldPath": "formatId",
"columnName": "type", "columnName": "formatId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "formatDesc",
"columnName": "formatDesc",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
@ -197,6 +203,12 @@
"columnName": "website", "columnName": "website",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
},
{
"fieldPath": "downloadSize",
"columnName": "downloadSize",
"affinity": "TEXT",
"notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
@ -212,7 +224,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '12ee531d801d7e6e3fd888f4907adc81')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1709c1d446102722d4dc7f2cb96cd40e')"
] ]
} }
} }

View file

@ -1,192 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 7,
"identityHash": "9951239671c916d8805c4156bb69cb6b",
"entities": [
{
"tableName": "results",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `videoId` TEXT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `downloadedAudio` INTEGER NOT NULL, `downloadedVideo` INTEGER NOT NULL, `isPlaylistItem` INTEGER NOT NULL, `website` TEXT NOT NULL, `downloadingAudio` INTEGER NOT NULL, `downloadingVideo` INTEGER NOT NULL, `playlistTitle` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"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": "downloadedAudio",
"columnName": "downloadedAudio",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "downloadedVideo",
"columnName": "downloadedVideo",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPlaylistItem",
"columnName": "isPlaylistItem",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadingAudio",
"columnName": "downloadingAudio",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "downloadingVideo",
"columnName": "downloadingVideo",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "playlistTitle",
"columnName": "playlistTitle",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"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` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `isQueuedDownload` 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": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadPath",
"columnName": "downloadPath",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isQueuedDownload",
"columnName": "isQueuedDownload",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"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, '9951239671c916d8805c4156bb69cb6b')"
]
}
}

View file

@ -1,7 +1,6 @@
package com.deniscerri.ytdlnis.adapter; package com.deniscerri.ytdlnis.adapter;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.ColorMatrix; import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter; import android.graphics.ColorMatrixColorFilter;
@ -14,40 +13,51 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.deniscerri.ytdlnis.R; import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.database.Video;
import com.deniscerri.ytdlnis.database.models.HistoryItem; import com.deniscerri.ytdlnis.database.models.HistoryItem;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import java.io.File; import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<DownloadsRecyclerViewAdapter.ViewHolder> { public class HistoryRecyclerViewAdapter extends ListAdapter<HistoryItem, HistoryRecyclerViewAdapter.ViewHolder> {
private List<HistoryItem> videoList; private ArrayList<Integer> checkedItems;
private ArrayList<Integer> checkedVideos;
private ArrayList<String> websites;
private final OnItemClickListener onItemClickListener; private final OnItemClickListener onItemClickListener;
private Activity activity; private Activity activity;
public DownloadsRecyclerViewAdapter(OnItemClickListener onItemClickListener, Activity activity){ public HistoryRecyclerViewAdapter(OnItemClickListener onItemClickListener, Activity activity) {
this.videoList = new ArrayList<>(); super(DIFF_CALLBACK);
this.websites = new ArrayList<>(); this.checkedItems = new ArrayList<>();
this.checkedVideos = new ArrayList<>();
this.onItemClickListener = onItemClickListener; this.onItemClickListener = onItemClickListener;
this.activity = activity; this.activity = activity;
} }
private static final DiffUtil.ItemCallback<HistoryItem> DIFF_CALLBACK = new DiffUtil.ItemCallback<HistoryItem>() {
@Override
public boolean areItemsTheSame(@NonNull HistoryItem oldItem, @NonNull HistoryItem newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull HistoryItem oldItem, @NonNull HistoryItem newItem) {
return oldItem.getTime() == newItem.getTime();
}
};
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
return super.getItemViewType(position); return super.getItemViewType(position);
@ -68,27 +78,25 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<Downloads
View cardView = LayoutInflater.from(parent.getContext()) View cardView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.downloads_card, parent, false); .inflate(R.layout.downloads_card, parent, false);
return new DownloadsRecyclerViewAdapter.ViewHolder(cardView, onItemClickListener); return new HistoryRecyclerViewAdapter.ViewHolder(cardView, onItemClickListener);
} }
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
HistoryItem video = videoList.get(position); HistoryItem video = getItem(position);
Log.e("AAA", video.toString()); Log.e("AAA", String.valueOf(position));
MaterialCardView card = holder.cardView; MaterialCardView card = holder.cardView;
// THUMBNAIL ---------------------------------- // THUMBNAIL ----------------------------------
ImageView thumbnail = card.findViewById(R.id.downloads_image_view); ImageView thumbnail = card.findViewById(R.id.downloads_image_view);
String imageURL= video.getThumb(); String imageURL= video.getThumb();
Handler uiHandler = new Handler(Looper.getMainLooper());
if (!imageURL.isEmpty()){ if (!imageURL.isEmpty()){
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(() -> Picasso.get().load(imageURL).into(thumbnail)); uiHandler.post(() -> Picasso.get().load(imageURL).into(thumbnail));
thumbnail.setColorFilter(Color.argb(70, 0, 0, 0));
}else { }else {
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(() -> Picasso.get().load(R.color.black).into(thumbnail)); uiHandler.post(() -> Picasso.get().load(R.color.black).into(thumbnail));
thumbnail.setColorFilter(Color.argb(70, 0, 0, 0));
} }
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0));
// TITLE ---------------------------------- // TITLE ----------------------------------
TextView videoTitle = card.findViewById(R.id.downloads_title); TextView videoTitle = card.findViewById(R.id.downloads_title);
@ -110,8 +118,22 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<Downloads
// TIME DOWNLOADED ---------------------------------- // TIME DOWNLOADED ----------------------------------
TextView datetime = card.findViewById(R.id.downloads_info_time); TextView datetime = card.findViewById(R.id.downloads_info_time);
String downloadedTime = video.getTime(); long time = video.getTime();
if (downloadedTime.isEmpty()) downloadedTime = activity.getString(R.string.currently_downloading) + " " + video.getType(); String downloadedTime;
if (time == 0){
downloadedTime = activity.getString(R.string.currently_downloading) + " " + video.getType();
}else{
Calendar cal = Calendar.getInstance();
Date date = new Date(time*1000L);
cal.setTime(date);
int day = cal.get(Calendar.DAY_OF_MONTH);
String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
int year = cal.get(Calendar.YEAR);
DateFormat formatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
String timeString = formatter.format(date);
downloadedTime = day + " " + month + " " + year + " - " + timeString;
}
datetime.setText(downloadedTime); datetime.setText(downloadedTime);
// BUTTON ---------------------------------- // BUTTON ----------------------------------
@ -141,7 +163,7 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<Downloads
if (btn.hasOnClickListeners()) btn.setOnClickListener(null); if (btn.hasOnClickListeners()) btn.setOnClickListener(null);
if(checkedVideos.contains(position)){ if(checkedItems.contains(position)){
card.setChecked(true); card.setChecked(true);
card.setStrokeWidth(5); card.setStrokeWidth(5);
}else{ }else{
@ -155,35 +177,25 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<Downloads
return true; return true;
}); });
card.setOnClickListener(view -> { card.setOnClickListener(view -> {
if(checkedVideos.size() > 0){ if(checkedItems.size() > 0){
checkCard(card, position); checkCard(card, video.getId());
}else{ }else{
onItemClickListener.onCardClick(position, finalFilePresent); onItemClickListener.onCardClick(video.getId(), finalFilePresent);
} }
}); });
} }
public void setVideoList(List<HistoryItem> list){
videoList.clear();
videoList.addAll(list);
notifyDataSetChanged();
}
private void checkCard(MaterialCardView card, int position){ private void checkCard(MaterialCardView card, int videoID){
if(card.isChecked()){ if(card.isChecked()){
card.setStrokeWidth(0); card.setStrokeWidth(0);
checkedVideos.remove(Integer.valueOf(position)); checkedItems.remove(videoID);
}else{ }else{
card.setStrokeWidth(5); card.setStrokeWidth(5);
checkedVideos.add(position); checkedItems.add(videoID);
} }
card.setChecked(!card.isChecked()); card.setChecked(!card.isChecked());
onItemClickListener.onCardSelect(position, card.isChecked()); onItemClickListener.onCardSelect(videoID, card.isChecked());
}
@Override
public int getItemCount() {
return videoList.size();
} }
public interface OnItemClickListener { public interface OnItemClickListener {
@ -192,44 +204,12 @@ public class DownloadsRecyclerViewAdapter extends RecyclerView.Adapter<Downloads
void onButtonClick(int position); void onButtonClick(int position);
} }
public ArrayList<String> getWebsites(){
return websites;
}
public void updateWebsiteList(){
websites = new ArrayList<>();
for (HistoryItem video : videoList){
if (!websites.contains(video.getWebsite())) websites.add(video.getWebsite());
}
}
public void clear(){
int size = videoList.size();
videoList.clear();
websites.clear();
notifyItemRangeRemoved(0, size);
}
public void clearCheckedVideos(){ public void clearCheckedVideos(){
int size = checkedVideos.size(); int size = checkedItems.size();
for (int i = 0; i < size; i++){ for (int i = 0; i < size; i++){
int position = checkedVideos.get(i); int position = checkedItems.get(i);
notifyItemChanged(position); notifyItemChanged(position);
} }
checkedVideos.clear(); checkedItems.clear();
} }
public void add(ArrayList<HistoryItem> vids){
int position = videoList.size() + 1;
videoList.addAll(vids);
notifyItemRangeInserted(position, vids.size());
updateWebsiteList();
}
public void remove(int index){
videoList.remove(index);
notifyItemRemoved(index);
updateWebsiteList();
}
} }

View file

@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.dao
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.util.FileUtil
@Dao @Dao
interface HistoryDao { interface HistoryDao {
@ -12,7 +11,7 @@ interface HistoryDao {
"CASE WHEN :sort = 'ASC' THEN id END ASC," + "CASE WHEN :sort = 'ASC' THEN id END ASC," +
"CASE WHEN :sort = 'DESC' THEN id END DESC," + "CASE WHEN :sort = 'DESC' THEN id END DESC," +
"CASE WHEN :sort = '' THEN id END DESC ") "CASE WHEN :sort = '' THEN id END DESC ")
fun getHistory(query : String, format : String, site : String, sort : String) : LiveData<List<HistoryItem>> fun getHistory(query : String, format : String, site : String, sort : String) : List<HistoryItem>
@Query("SELECT * FROM history") @Query("SELECT * FROM history")
fun getAllHistory() : LiveData<List<HistoryItem>> fun getAllHistory() : LiveData<List<HistoryItem>>
@ -23,8 +22,8 @@ interface HistoryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(item: HistoryItem) suspend fun insert(item: HistoryItem)
@Delete @Query("DELETE FROM history WHERE id=:id")
suspend fun delete(item: HistoryItem) suspend fun delete(id: Int)
@Query("DELETE FROM history") @Query("DELETE FROM history")
suspend fun deleteAll() suspend fun deleteAll()

View file

@ -12,7 +12,9 @@ data class DownloadItem(
val author: String, val author: String,
val duration: String, val duration: String,
val thumb: String, val thumb: String,
val type: String, val formatId: Int,
val formatDesc: String,
val downloadPath: String, val downloadPath: String,
val website: String val website: String,
val downloadSize: String
) )

View file

@ -6,14 +6,14 @@ import androidx.room.PrimaryKey
@Entity(tableName = "history") @Entity(tableName = "history")
data class HistoryItem( data class HistoryItem(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
val id: Int, var id: Int,
val url: String, val url: String,
val title: String, val title: String,
val author: String, val author: String,
val duration: String, val duration: String,
val thumb: String, val thumb: String,
val type: String, val type: String,
val time: String, val time: Long,
val downloadPath: String, val downloadPath: String,
val website: String val website: String
//val isQueuedDownload: Int //val isQueuedDownload: Int

View file

@ -3,6 +3,8 @@ package com.deniscerri.ytdlnis.database.models
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import com.yausername.youtubedl_android.mapper.VideoFormat
import com.yausername.youtubedl_android.mapper.VideoInfo
@Entity(tableName = "results") @Entity(tableName = "results")
data class ResultItem( data class ResultItem(

View file

@ -1,26 +1,41 @@
package com.deniscerri.ytdlnis.database.repository package com.deniscerri.ytdlnis.database.repository
import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.room.Transaction import androidx.room.Transaction
import com.deniscerri.ytdlnis.database.dao.DownloadDao import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.HistoryDao import com.deniscerri.ytdlnis.database.dao.HistoryDao
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import java.io.File
class HistoryRepository(private val historyDao: HistoryDao) { class HistoryRepository(private val historyDao: HistoryDao) {
val allHistory : LiveData<List<HistoryItem>> = historyDao.getAllHistory() val items : LiveData<List<HistoryItem>> = historyDao.getAllHistory()
enum class HistorySort{
DESC, ASC
}
suspend fun getItem(id: Int) : HistoryItem?{ suspend fun getItem(id: Int) : HistoryItem {
return historyDao.getHistoryItem(id) return historyDao.getHistoryItem(id)
} }
fun getFiltered(query : String, format : String, site : String, sort: HistorySort) : List<HistoryItem> {
return historyDao.getHistory(query, format, site, sort.toString())
}
suspend fun insert(item: HistoryItem){ suspend fun insert(item: HistoryItem){
historyDao.insert(item) historyDao.insert(item)
} }
suspend fun delete(item: HistoryItem){ suspend fun delete(item: HistoryItem, deleteFile: Boolean){
historyDao.delete(item) Log.e("ASd", item.id.toString())
historyDao.delete(item.id)
if (deleteFile){
val fileUtil = FileUtil()
fileUtil.deleteFile(item.downloadPath)
}
} }
suspend fun deleteAll(){ suspend fun deleteAll(){
@ -37,9 +52,9 @@ class HistoryRepository(private val historyDao: HistoryDao) {
suspend fun clearDeletedHistory(){ suspend fun clearDeletedHistory(){
val fileUtil = FileUtil() val fileUtil = FileUtil()
allHistory.value?.forEach { item -> items.value?.forEach { item ->
if (!fileUtil.exists(item.downloadPath)){ if (!fileUtil.exists(item.downloadPath)){
delete(item) delete(item, false)
} }
} }
} }

View file

@ -1,33 +1,88 @@
package com.deniscerri.ytdlnis.database.viewmodel package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Application import android.app.Application
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.database.DBManager import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.repository.HistoryRepository import com.deniscerri.ytdlnis.database.repository.HistoryRepository
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class HistoryViewModel(application: Application) : AndroidViewModel(application) { class HistoryViewModel(application: Application) : AndroidViewModel(application) {
private val repository : HistoryRepository private val repository : HistoryRepository
val allHistory : LiveData<List<HistoryItem>> private val sortType = MutableLiveData(HistorySort.DESC)
private val websiteFilter = MutableLiveData("")
private val queryFilter = MutableLiveData("")
private val formatFilter = MutableLiveData("")
val allItems : LiveData<List<HistoryItem>>
private var _items = MediatorLiveData<List<HistoryItem>>()
init { init {
val dao = DBManager.getInstance(application).historyDao val dao = DBManager.getInstance(application).historyDao
repository = HistoryRepository(dao) repository = HistoryRepository(dao)
allHistory = repository.allHistory allItems = repository.items
_items.addSource(allItems, Observer {
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(formatFilter, Observer {
Log.e("aa", "audio");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(sortType, Observer {
Log.e("aa", "asssssssssssss");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(websiteFilter, Observer {
Log.e("Aa", "website")
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(queryFilter, Observer {
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
}
fun getFilteredList() : LiveData<List<HistoryItem>>{
return _items;
}
fun setSorting(sort: HistorySort){
Log.e("aa", "asssssssssssss");
sortType.value = sort
}
fun setWebsiteFilter(filter : String){
websiteFilter.value = filter
}
fun setQueryFilter(filter: String){
queryFilter.value = filter
}
fun setFormatFilter(filter: String){
Log.e("aa", "audio");
formatFilter.value = filter
}
fun filter(query : String, format : String, site : String, sort: HistorySort) = viewModelScope.launch(Dispatchers.IO){
_items.postValue(repository.getFiltered(query, format, site, sort))
} }
fun insert(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){ fun insert(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
repository.insert(item) repository.insert(item)
} }
fun delete(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){ fun delete(item: HistoryItem, deleteFile: Boolean) = viewModelScope.launch(Dispatchers.IO){
repository.delete(item) repository.delete(item, deleteFile)
} }
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) { fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {

View file

@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui
import android.app.Activity import android.app.Activity
import android.content.* import android.content.*
import android.net.Uri import android.net.Uri
import android.os.Binder
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -15,22 +14,17 @@ import android.widget.*
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.DownloadsRecyclerViewAdapter import com.deniscerri.ytdlnis.adapter.HistoryRecyclerViewAdapter
import com.deniscerri.ytdlnis.database.DatabaseManager import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.Video
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdlnis.databinding.FragmentDownloadsBinding import com.deniscerri.ytdlnis.databinding.FragmentDownloadsBinding
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.service.DownloadInfo
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.facebook.shimmer.ShimmerFrameLayout import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
@ -40,50 +34,40 @@ import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import java.io.File import java.io.File
/** /**
* A fragment representing a list of Items. * A fragment representing a list of Items.
*/ */
class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickListener, class DownloadsFragment : Fragment(), HistoryRecyclerViewAdapter.OnItemClickListener,
View.OnClickListener, OnLongClickListener { OnClickListener, OnLongClickListener {
private lateinit var historyViewModel : HistoryViewModel private lateinit var historyViewModel : HistoryViewModel
private var downloading = false private var downloading = false
private var fragmentView: View? = null private var fragmentView: View? = null
private var databaseManager: DatabaseManager? = null private var databaseManager: DatabaseManager? = null
var activity: Activity? = null private var activity: Activity? = null
var mainActivity: MainActivity? = null private var mainActivity: MainActivity? = null
var fragmentContext: Context? = null private var fragmentContext: Context? = null
private var layoutinflater: LayoutInflater? = null private var layoutinflater: LayoutInflater? = null
private var shimmerCards: ShimmerFrameLayout? = null private var shimmerCards: ShimmerFrameLayout? = null
private var topAppBar: MaterialToolbar? = null private var topAppBar: MaterialToolbar? = null
private var recyclerView: RecyclerView? = null private var recyclerView: RecyclerView? = null
private var downloadsRecyclerViewAdapter: DownloadsRecyclerViewAdapter? = null private var historyRecyclerViewAdapter: HistoryRecyclerViewAdapter? = null
private var bottomSheet: BottomSheetDialog? = null private var bottomSheet: BottomSheetDialog? = null
private var sortSheet: BottomSheetDialog? = null private var sortSheet: BottomSheetDialog? = null
private var uiHandler: Handler? = null private var uiHandler: Handler? = null
private var no_results: RelativeLayout? = null private var noResults: RelativeLayout? = null
private var selectionChips: LinearLayout? = null private var selectionChips: LinearLayout? = null
private var websiteGroup: ChipGroup? = null private var websiteGroup: ChipGroup? = null
private var downloadsObjects: List<HistoryItem?>? = null private var downloadsList: List<HistoryItem?>? = null
var selectedObjects: ArrayList<Video?>? = null private var allDownloadsList: List<HistoryItem?>? = null
private var progressBar: LinearProgressIndicator? = null private var selectedObjects: ArrayList<HistoryItem>? = null
private var deleteFab: ExtendedFloatingActionButton? = null private var deleteFab: ExtendedFloatingActionButton? = null
private var fileUtil: FileUtil? = null private var fileUtil: FileUtil? = null
private var format = ""
private var website = ""
private var sort = "DESC"
private var searchQuery = ""
private var _binding : FragmentDownloadsBinding? = null private var _binding : FragmentDownloadsBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@ -100,9 +84,10 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
fragmentContext = context fragmentContext = context
layoutinflater = LayoutInflater.from(context)
shimmerCards = view.findViewById(R.id.shimmer_downloads_framelayout) shimmerCards = view.findViewById(R.id.shimmer_downloads_framelayout)
topAppBar = view.findViewById(R.id.downloads_toolbar) topAppBar = view.findViewById(R.id.downloads_toolbar)
no_results = view.findViewById(R.id.downloads_no_results) noResults = view.findViewById(R.id.downloads_no_results)
selectionChips = view.findViewById(R.id.downloads_selection_chips) selectionChips = view.findViewById(R.id.downloads_selection_chips)
websiteGroup = view.findViewById(R.id.website_chip_group) websiteGroup = view.findViewById(R.id.website_chip_group)
deleteFab = view.findViewById(R.id.delete_selected_fab) deleteFab = view.findViewById(R.id.delete_selected_fab)
@ -110,77 +95,58 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
deleteFab?.tag = "deleteSelected" deleteFab?.tag = "deleteSelected"
deleteFab?.setOnClickListener(this) deleteFab?.setOnClickListener(this)
uiHandler = Handler(Looper.getMainLooper()) uiHandler = Handler(Looper.getMainLooper())
downloadsObjects = ArrayList()
selectedObjects = ArrayList() selectedObjects = ArrayList()
downloading = mainActivity!!.isDownloadServiceRunning() downloading = mainActivity!!.isDownloadServiceRunning()
downloadsObjects = mutableListOf() downloadsList = mutableListOf()
allDownloadsList = mutableListOf()
downloadsRecyclerViewAdapter = historyRecyclerViewAdapter =
DownloadsRecyclerViewAdapter(this, activity) HistoryRecyclerViewAdapter(
this,
activity
)
recyclerView = view.findViewById(R.id.recyclerviewdownloadss) recyclerView = view.findViewById(R.id.recyclerviewdownloadss)
recyclerView?.layoutManager = LinearLayoutManager(context) recyclerView?.layoutManager = LinearLayoutManager(context)
recyclerView?.adapter = downloadsRecyclerViewAdapter recyclerView?.adapter = historyRecyclerViewAdapter
downloadsRecyclerViewAdapter!!.clear() noResults?.visibility = GONE
no_results?.visibility = GONE
selectionChips?.visibility = VISIBLE selectionChips?.visibility = VISIBLE
shimmerCards?.visibility = GONE shimmerCards?.visibility = GONE
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java] historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
historyViewModel.allHistory.observe(viewLifecycleOwner) { historyViewModel.allItems.observe(viewLifecycleOwner) {
downloadsRecyclerViewAdapter!!.setVideoList(it); allDownloadsList = it
Toast.makeText(context, "CHANGED", Toast.LENGTH_SHORT).show() if(it.isEmpty()){
noResults!!.visibility = VISIBLE
selectionChips!!.visibility = GONE
websiteGroup!!.removeAllViews()
}else{
noResults!!.visibility = GONE
selectionChips!!.visibility = VISIBLE
updateWebsiteChips(it)
}
} }
historyViewModel.getFilteredList().observe(viewLifecycleOwner) {
historyRecyclerViewAdapter!!.submitList(it)
downloadsList = it
}
initMenu() initMenu()
//initChips() initChips()
// initCards()
} }
// fun initCards() {
// shimmerCards!!.startShimmer()
// shimmerCards!!.visibility = View.VISIBLE
// downloadsRecyclerViewAdapter!!.clear()
// no_results!!.visibility = View.GONE
// selectionChips!!.visibility = View.VISIBLE
// databaseManager = DatabaseManager(context)
// try {
// val thread = Thread {
// if (!downloading) databaseManager!!.clearDownloadingHistory()
// downloadsObjects = databaseManager!!.getHistory("", format, website, sort)
// uiHandler!!.post {
// downloadsRecyclerViewAdapter!!.add(downloadsObjects)
// shimmerCards!!.stopShimmer()
// shimmerCards!!.visibility = View.GONE
// updateWebsiteChips()
// }
// if ((downloadsObjects as ArrayList<Video>?)?.size == 0) {
// uiHandler!!.post {
// no_results!!.visibility = View.VISIBLE
// selectionChips!!.visibility = View.GONE
// websiteGroup!!.removeAllViews()
// }
// }
// databaseManager!!.close()
// }
// thread.start()
// } catch (e: Exception) {
// Log.e(TAG, e.toString())
// }
// }
//
fun scrollToTop() { fun scrollToTop() {
// recyclerView!!.scrollToPosition(0) recyclerView!!.scrollToPosition(0)
// Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
// (topAppBar!!.parent as AppBarLayout).setExpanded( (topAppBar!!.parent as AppBarLayout).setExpanded(
// true, true,
// true true
// ) )
// } }
} }
private fun initMenu() { private fun initMenu() {
@ -194,7 +160,6 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
return true return true
} }
} }
val toolbar = fragmentView!!.findViewById<MaterialToolbar>(R.id.downloads_toolbar)
topAppBar!!.menu.findItem(R.id.search_downloads) topAppBar!!.menu.findItem(R.id.search_downloads)
.setOnActionExpandListener(onActionExpandListener) .setOnActionExpandListener(onActionExpandListener)
val searchView = topAppBar!!.menu.findItem(R.id.search_downloads).actionView as SearchView? val searchView = topAppBar!!.menu.findItem(R.id.search_downloads).actionView as SearchView?
@ -203,301 +168,228 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
databaseManager = DatabaseManager(context) databaseManager = DatabaseManager(context)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
// searchQuery = query topAppBar!!.menu.findItem(R.id.search_downloads).collapseActionView()
// topAppBar!!.menu.findItem(R.id.search_downloads).collapseActionView() historyViewModel.setQueryFilter(query)
// downloadsObjects = databaseManager!!.getHistory(query, format, website, sort)
// downloadsRecyclerViewAdapter!!.clear()
// downloadsRecyclerViewAdapter!!.add(downloadsObjects)
// if ((downloadsObjects as ArrayList<Video>?)?.size == 0) {
// no_results!!.visibility = View.VISIBLE
// selectionChips!!.visibility = View.GONE
// websiteGroup!!.removeAllViews()
// }
return true return true
} }
override fun onQueryTextChange(newText: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
// searchQuery = newText historyViewModel.setQueryFilter(newText)
// downloadsObjects = databaseManager!!.getHistory(newText, format, website, sort)
// downloadsRecyclerViewAdapter!!.clear()
// downloadsRecyclerViewAdapter!!.add(downloadsObjects)
// if ((downloadsObjects as ArrayList<Video>?)?.size == 0) {
// no_results!!.visibility = View.VISIBLE
// selectionChips!!.visibility = View.GONE
// } else {
// no_results!!.visibility = View.GONE
// selectionChips!!.visibility = View.VISIBLE
// }
return true return true
} }
}) })
topAppBar!!.setOnClickListener { view: View? -> scrollToTop() } topAppBar!!.setOnClickListener { scrollToTop() }
topAppBar!!.setOnMenuItemClickListener { m: MenuItem -> topAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
val itemID = m.itemId when (m.itemId) {
if (itemID == R.id.remove_downloads) { R.id.remove_downloads -> {
// if (downloadsObjects!!.size == 0) { if(allDownloadsList!!.isEmpty()){
// Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
// return@setOnMenuItemClickListener true }else{
// } val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!) deleteDialog.setTitle(getString(R.string.confirm_delete_history))
// delete_dialog.setTitle(getString(R.string.confirm_delete_history)) deleteDialog.setMessage(getString(R.string.confirm_delete_history_desc))
// delete_dialog.setMessage(getString(R.string.confirm_delete_history_desc)) deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int -> historyViewModel.deleteAll()
// databaseManager!!.clearHistory() }
// downloadsRecyclerViewAdapter!!.clear() deleteDialog.show()
// downloadsObjects!!.clear() }
// no_results!!.visibility = View.VISIBLE }
// selectionChips!!.visibility = View.GONE R.id.remove_deleted_downloads -> {
// websiteGroup!!.removeAllViews() if(allDownloadsList!!.isEmpty()){
// } Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
// delete_dialog.show() }else{
} else if (itemID == R.id.remove_deleted_downloads) { val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
// if (downloadsObjects!!.size == 0) { deleteDialog.setTitle(getString(R.string.confirm_delete_history))
// Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show() deleteDialog.setMessage(getString(R.string.confirm_delete_history_desc))
// return@setOnMenuItemClickListener true deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
// } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!) historyViewModel.clearDeleted()
// delete_dialog.setTitle(getString(R.string.confirm_delete_history)) }
// delete_dialog.setMessage(getString(R.string.confirm_delete_history_deleted_desc)) deleteDialog.show()
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() } }
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int -> }
// databaseManager!!.clearDeletedHistory() R.id.remove_duplicates -> {
// initCards() if(allDownloadsList!!.isEmpty()){
// } Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
// delete_dialog.show() }else{
} else if (itemID == R.id.remove_duplicates) { val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
// if (downloadsObjects!!.size == 0) { deleteDialog.setTitle(getString(R.string.confirm_delete_history))
// Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show() deleteDialog.setMessage(getString(R.string.confirm_delete_history_desc))
// return@setOnMenuItemClickListener true deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
// } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!) historyViewModel.deleteDuplicates()
// delete_dialog.setTitle(getString(R.string.confirm_delete_history)) }
// delete_dialog.setMessage(getString(R.string.confirm_delete_history_duplicates_desc)) deleteDialog.show()
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() } }
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int -> }
// databaseManager!!.clearDuplicateHistory() R.id.remove_downloading -> {
// initCards()
// } }
// delete_dialog.show()
} else if (itemID == R.id.remove_downloading) {
// if (downloadsObjects!!.size == 0) {
// Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
// return@setOnMenuItemClickListener true
// }
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!)
// delete_dialog.setTitle(getString(R.string.confirm_delete_history))
// delete_dialog.setMessage(getString(R.string.confirm_delete_downloading_desc))
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() }
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int ->
// databaseManager!!.clearDownloadingHistory()
// mainActivity!!.cancelDownloadService()
// initCards()
// }
// delete_dialog.show()
} }
true true
} }
} }
// private fun initChips() {
// //sort and history/downloading switch private fun initChips() {
// val sortChip = fragmentView!!.findViewById<Chip>(R.id.sort_chip) val sortChip = fragmentView!!.findViewById<Chip>(R.id.sortChip)
// sortChip.setOnClickListener { view: View? -> sortChip.setOnClickListener {
// sortSheet = BottomSheetDialog(fragmentContext!!) sortSheet = BottomSheetDialog(requireContext())
// sortSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE) sortSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
// sortSheet!!.setContentView(R.layout.downloads_sort_sheet) sortSheet!!.setContentView(R.layout.downloads_sort_sheet)
// val newest = sortSheet!!.findViewById<TextView>(R.id.newest) val newest = sortSheet!!.findViewById<TextView>(R.id.newest)
// val oldest = sortSheet!!.findViewById<TextView>(R.id.oldest) val oldest = sortSheet!!.findViewById<TextView>(R.id.oldest)
// newest!!.setOnClickListener { view1: View? -> newest!!.setOnClickListener {
// sort = "DESC" historyViewModel.setSorting(HistorySort.DESC)
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) sortSheet!!.cancel()
// downloadsRecyclerViewAdapter!!.clear() }
// downloadsRecyclerViewAdapter!!.add(downloadsObjects) oldest!!.setOnClickListener {
// sortSheet!!.cancel() historyViewModel.setSorting(HistorySort.ASC)
// } sortSheet!!.cancel()
// oldest!!.setOnClickListener { view1: View? -> }
// sort = "ASC" val cancel = sortSheet!!.findViewById<TextView>(R.id.cancel)
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) cancel!!.setOnClickListener { sortSheet!!.cancel() }
// downloadsRecyclerViewAdapter!!.clear() sortSheet!!.show()
// downloadsRecyclerViewAdapter!!.add(downloadsObjects) sortSheet!!.window!!.setLayout(
// sortSheet!!.cancel() ViewGroup.LayoutParams.MATCH_PARENT,
// } ViewGroup.LayoutParams.MATCH_PARENT
// val cancel = sortSheet!!.findViewById<TextView>(R.id.cancel) )
// cancel!!.setOnClickListener { view1: View? -> sortSheet!!.cancel() } }
// sortSheet!!.show()
// sortSheet!!.window!!.setLayout( //format
// ViewGroup.LayoutParams.MATCH_PARENT, val audio = fragmentView!!.findViewById<Chip>(R.id.audio_chip)
// ViewGroup.LayoutParams.MATCH_PARENT audio.setOnClickListener {
// ) if (audio.isChecked) {
// } historyViewModel.setFormatFilter("audio")
// audio.isChecked = true
// //format } else {
// val audio = fragmentView!!.findViewById<Chip>(R.id.audio_chip) historyViewModel.setFormatFilter("")
// audio.setOnClickListener { view: View? -> audio.isChecked = false
// if (audio.isChecked) { }
// format = "audio" }
// if (recyclerView!!.visibility == View.GONE) { val video = fragmentView!!.findViewById<Chip>(R.id.video_chip)
// } video.setOnClickListener {
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) if (video.isChecked) {
// audio.isChecked = true historyViewModel.setFormatFilter("video")
// } else { video.isChecked = true
// format = "" } else {
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) historyViewModel.setFormatFilter("")
// audio.isChecked = false video.isChecked = false
// } }
// downloadsRecyclerViewAdapter!!.clear() }
// downloadsRecyclerViewAdapter!!.add(downloadsObjects) }
// }
// val video = fragmentView!!.findViewById<Chip>(R.id.video_chip) private fun updateWebsiteChips(list : List<HistoryItem>) {
// video.setOnClickListener { view: View? -> val websites = mutableListOf<String>()
// if (video.isChecked) { for (item in list){
// format = "video" if (!websites.contains(item.website)) websites.add(item.website)
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) }
// video.isChecked = true websiteGroup!!.removeAllViews()
// } else { //val websites = downloadsRecyclerViewAdapter!!.websites
// format = "" for (i in websites.indices) {
// downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort) val w = websites[i]
// video.isChecked = false val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
// } tmp.text = w
// downloadsRecyclerViewAdapter!!.clear() tmp.id = i
// downloadsRecyclerViewAdapter!!.add(downloadsObjects) tmp.setOnClickListener {
// } Log.e(TAG, tmp.isChecked.toString())
// } if (tmp.isChecked) {
// historyViewModel.setWebsiteFilter(tmp.text as String)
// private fun updateWebsiteChips() { tmp.isChecked = true
// websiteGroup!!.removeAllViews() } else {
// val websites = downloadsRecyclerViewAdapter!!.websites historyViewModel.setWebsiteFilter("")
// for (i in websites.indices) { tmp.isChecked = false
// val w = websites[i] }
// val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip }
// tmp.text = w websiteGroup!!.addView(tmp)
// tmp.id = i }
// tmp.setOnClickListener { view: View -> }
// if (tmp.isChecked) {
// website = tmp.text as String
// downloadsObjects =
// databaseManager!!.getHistory(searchQuery, format, website, sort)
// websiteGroup!!.check(view.id)
// } else {
// website = ""
// downloadsObjects =
// databaseManager!!.getHistory(searchQuery, format, website, sort)
// websiteGroup!!.clearCheck()
// }
// downloadsRecyclerViewAdapter!!.clear()
// downloadsRecyclerViewAdapter!!.add(downloadsObjects)
// }
// websiteGroup!!.addView(tmp)
// }
// }
override fun onClick(v: View) { override fun onClick(v: View) {
// val id = v.id when (v.id) {
// if (id == R.id.bottomsheet_remove_button) { R.id.bottomsheet_remove_button -> {
// removedownloadsItem(v.tag as Int) removeItem(v.tag as Int)
// } else if (id == R.id.bottom_sheet_link) { }
// openLinkIntent(v.tag as Int) R.id.bottom_sheet_link -> {
// } else if (id == R.id.bottomsheet_open_file_button) { openLinkIntent(v.tag as Int)
// openFileIntent(v.tag as Int) }
// } else if (id == R.id.delete_selected_fab) { R.id.bottomsheet_open_file_button -> {
// removeSelectedItems() openFileIntent(v.tag as Int)
// } }
R.id.delete_selected_fab -> {
removeSelectedItems()
}
}
} }
override fun onLongClick(v: View): Boolean { override fun onLongClick(v: View): Boolean {
// val id = v.id val id = v.id
// if (id == R.id.bottom_sheet_link) { if (id == R.id.bottom_sheet_link) {
// copyLinkToClipBoard(v.tag as Int) copyLinkToClipBoard(v.tag as Int)
// return true return true
// } }
return false return false
} }
// private fun removeSelectedItems() { private fun removeSelectedItems() {
// if (bottomSheet != null) bottomSheet!!.hide() if (bottomSheet != null) bottomSheet!!.hide()
// val delete_file = booleanArrayOf(false) val deleteFile = booleanArrayOf(false)
// databaseManager = DatabaseManager(context) val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!) deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
// delete_dialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items)) deleteDialog.setMultiChoiceItems(
// delete_dialog.setMultiChoiceItems( arrayOf(getString(R.string.delete_files_too)),
// arrayOf(getString(R.string.delete_files_too)), booleanArrayOf(false)
// booleanArrayOf(false) ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
// ) { dialogInterface: DialogInterface?, i: Int, b: Boolean -> delete_file[0] = b } deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int -> for (item in selectedObjects!!){
// for (j in selectedObjects!!.indices) { historyViewModel.delete(item, deleteFile[0])
// val v = selectedObjects!![j] }
// val position = downloadsObjects!!.indexOf(v) selectedObjects = ArrayList()
// downloadsObjects!!.remove(v) historyRecyclerViewAdapter!!.clearCheckedVideos()
// downloadsRecyclerViewAdapter!!.remove(position) deleteFab!!.visibility = GONE
// databaseManager!!.clearHistoryItem(v, delete_file[0]) }
// } deleteDialog.show()
// updateWebsiteChips() }
// databaseManager!!.close()
// selectedObjects = ArrayList()
// downloadsRecyclerViewAdapter!!.clearCheckedVideos()
// deleteFab!!.visibility = View.GONE
// if (downloadsObjects!!.size == 0) {
// uiHandler!!.post {
// no_results!!.visibility = View.VISIBLE
// selectionChips!!.visibility = View.GONE
// websiteGroup!!.removeAllViews()
// }
// }
// }
// delete_dialog.show()
// }
//
// private fun removedownloadsItem(position: Int) {
// if (bottomSheet != null) bottomSheet!!.hide()
// val delete_file = booleanArrayOf(false)
// databaseManager = DatabaseManager(context)
// val v = downloadsObjects!![position]
// val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!)
// delete_dialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + v!!.title + "\"!")
// delete_dialog.setMultiChoiceItems(
// arrayOf(getString(R.string.delete_file_too)),
// booleanArrayOf(false)
// ) { dialogInterface: DialogInterface?, i: Int, b: Boolean -> delete_file[0] = b }
// delete_dialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, i: Int -> dialogInterface.cancel() }
// delete_dialog.setPositiveButton(getString(R.string.ok)) { dialogInterface: DialogInterface?, i: Int ->
// downloadsObjects!!.removeAt(position)
// downloadsRecyclerViewAdapter!!.remove(position)
// updateWebsiteChips()
// databaseManager!!.clearHistoryItem(v, delete_file[0])
// databaseManager!!.close()
// if (downloadsObjects!!.size == 0) {
// uiHandler!!.post {
// no_results!!.visibility = View.VISIBLE
// selectionChips!!.visibility = View.GONE
// websiteGroup!!.removeAllViews()
// }
// }
// }
// delete_dialog.show()
// }
//
// private fun copyLinkToClipBoard(position: Int) {
// val url = downloadsObjects!![position]!!.getURL()
// val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
// val clip = ClipData.newPlainText(getString(R.string.url), url)
// clipboard.setPrimaryClip(clip)
// if (bottomSheet != null) bottomSheet!!.hide()
// Toast.makeText(context, getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
// .show()
// }
//
// private fun openLinkIntent(position: Int) {
// val url = downloadsObjects!![position]!!.getURL()
// val i = Intent(Intent.ACTION_VIEW)
// i.data = Uri.parse(url)
// if (bottomSheet != null) bottomSheet!!.hide()
// startActivity(i)
// }
private fun openFileIntent(position: Int) { private fun removeItem(id: Int) {
val downloadPath = downloadsObjects!![position]!!.downloadPath if (bottomSheet != null) bottomSheet!!.hide()
val deleteFile = booleanArrayOf(false)
val v = findItem(id)
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + v!!.title + "\"!")
deleteDialog.setMultiChoiceItems(
arrayOf(getString(R.string.delete_file_too)),
booleanArrayOf(false)
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
historyViewModel.delete(v, deleteFile[0])
}
deleteDialog.show()
}
private fun copyLinkToClipBoard(id: Int) {
val url = findItem(id)?.url
val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.url), url)
clipboard.setPrimaryClip(clip)
if (bottomSheet != null) bottomSheet!!.hide()
Toast.makeText(context, getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
.show()
}
private fun openLinkIntent(id: Int) {
val url = findItem(id)?.url
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
if (bottomSheet != null) bottomSheet!!.hide()
startActivity(i)
}
private fun openFileIntent(id: Int) {
val downloadPath = findItem(id)!!.downloadPath
val file = File(downloadPath) val file = File(downloadPath)
val uri = FileProvider.getUriForFile( val uri = FileProvider.getUriForFile(
fragmentContext!!, fragmentContext!!,
@ -511,11 +403,11 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
startActivity(i) startActivity(i)
} }
override fun onCardClick(position: Int, isFilePresent: Boolean) { override fun onCardClick(id: Int, isFilePresent: Boolean) {
bottomSheet = BottomSheetDialog(fragmentContext!!) bottomSheet = BottomSheetDialog(fragmentContext!!)
bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE) bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet!!.setContentView(R.layout.downloads_bottom_sheet) bottomSheet!!.setContentView(R.layout.downloads_bottom_sheet)
val video = downloadsObjects!![position] val video = findItem(id)
val title = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_title) val title = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_title)
title!!.text = video!!.title title!!.text = video!!.title
val author = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_author) val author = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_author)
@ -523,14 +415,14 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
val link = bottomSheet!!.findViewById<Button>(R.id.bottom_sheet_link) val link = bottomSheet!!.findViewById<Button>(R.id.bottom_sheet_link)
val url = video.url val url = video.url
link!!.text = url link!!.text = url
link.tag = position link.tag = id
link.setOnClickListener(this) link.setOnClickListener(this)
link.setOnLongClickListener(this) link.setOnLongClickListener(this)
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button) val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.tag = position remove!!.tag = id
remove.setOnClickListener(this) remove.setOnClickListener(this)
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button) val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
openFile!!.tag = position openFile!!.tag = id
openFile.setOnClickListener(this) openFile.setOnClickListener(this)
if (!isFilePresent) openFile.visibility = GONE if (!isFilePresent) openFile.visibility = GONE
bottomSheet!!.show() bottomSheet!!.show()
@ -540,43 +432,33 @@ class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickLi
) )
} }
override fun onCardSelect(position: Int, add: Boolean) { override fun onCardSelect(id: Int, add: Boolean) {
// val video = downloadsObjects!![position] val item = findItem(id)
// if (add) selectedObjects!!.add(video) else selectedObjects!!.remove(video) if (add) selectedObjects!!.add(item!!)
// if (selectedObjects!!.size > 1) { else selectedObjects!!.remove(item)
// deleteFab!!.visibility = View.VISIBLE if (selectedObjects!!.size > 1) {
// } else { deleteFab!!.visibility = VISIBLE
// deleteFab!!.visibility = View.GONE } else {
// } deleteFab!!.visibility = GONE
}
} }
//
override fun onButtonClick(position: Int) { override fun onButtonClick(position: Int) {
// val vid = downloadsObjects!![position] // val vid = downloadsObjects!![position]
// try { // try {
// mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType) // //mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType)
// } catch (e: Exception) { // } catch (e: Exception) {
// val info = DownloadInfo() // val info = DownloadInfo()
// info.video = vid // info.video = vid
// info.downloadType = vid!!.downloadedType // info.downloadType = vid!!.downloadedType
// } // }
} }
//
fun findVideo(url: String, type: String): HistoryItem? { private fun findItem(id : Int): HistoryItem? {
for (i in downloadsObjects!!.indices) { return downloadsList?.find { it?.id == id }
val v = downloadsObjects!![i]
if (v!!.url == url && v.type == type) {
return v
}
}
return null
} }
companion object { companion object {
private const val TAG = "downloadsFragment" private const val TAG = "downloadsFragment"
fun newInstance(): DownloadsFragment {
val fragment = DownloadsFragment()
val args = Bundle()
return fragment
}
} }
} }

View file

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF" <vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24" android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18L6,18c-2.21,0 -4,-1.79 -4,-4 0,-2.05 1.53,-3.76 3.56,-3.97l1.07,-0.11 0.5,-0.95C8.08,7.14 9.94,6 12,6c2.62,0 4.88,1.86 5.39,4.43l0.3,1.5 1.53,0.11c1.56,0.1 2.78,1.41 2.78,2.96 0,1.65 -1.35,3 -3,3zM13.45,10h-2.9v3L8,13l4,4 4,-4h-2.55z"/> <path android:fillColor="@android:color/white" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
</vector> </vector>

View file

@ -50,12 +50,13 @@
app:singleSelection="false"> app:singleSelection="false">
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/sort_chip" android:id="@+id/sortChip"
style="@style/Widget.Material3.Chip.Assist" style="@style/Widget.Material3.Chip.Assist"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:chipIcon="@drawable/ic_down" android:onClick="sortBy"
android:text="@string/sort_by"/> android:text="@string/sort_by"
app:chipIcon="@drawable/ic_down" />
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>