dev init
This commit is contained in:
parent
51ff22abcd
commit
b330a5ba08
30 changed files with 1016 additions and 762 deletions
|
|
@ -113,7 +113,7 @@ dependencies {
|
|||
implementation "com.devbrackets.android:exomedia:4.3.0"
|
||||
|
||||
implementation("androidx.cardview:cardview:1.0.0")
|
||||
implementation("com.squareup.picasso:picasso:2.8")
|
||||
implementation("com.squareup.picasso:picasso:2.71828")
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
|
||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
||||
|
|
@ -131,4 +131,10 @@ dependencies {
|
|||
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVer"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVer"
|
||||
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofitVer"
|
||||
implementation "com.squareup.retrofit2:converter-gson:$retrofitVer"
|
||||
|
||||
implementation "org.kodein.di:kodein-di-generic-jvm:6.4.0"
|
||||
implementation "org.kodein.di:kodein-di-framework-android-x:$kodeinVer"
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".page.settings.SettingsActivity"
|
||||
android:name=".ui.settings.SettingsActivity"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".page.CustomCommandActivity"
|
||||
android:name=".ui.CustomCommandActivity"
|
||||
android:theme="@style/AppDefaultTheme"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:label="@string/run_command"
|
||||
|
|
|
|||
|
|
@ -5,13 +5,10 @@ import android.app.PendingIntent
|
|||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.SystemClock
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.Settings.Global
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
|
|
@ -19,7 +16,7 @@ import androidx.work.OneTimeWorkRequestBuilder
|
|||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.database.Video
|
||||
import com.deniscerri.ytdlnis.page.CustomCommandActivity
|
||||
import com.deniscerri.ytdlnis.ui.CustomCommandActivity
|
||||
import com.deniscerri.ytdlnis.service.DownloadInfo
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||
|
|
@ -29,7 +26,6 @@ import com.deniscerri.ytdlnis.work.FileTransferWorker
|
|||
import com.deniscerri.ytdlnis.work.FileTransferWorker.Companion.originDir
|
||||
import com.deniscerri.ytdlnis.work.FileTransferWorker.Companion.title
|
||||
import com.deniscerri.ytdlnis.work.FileTransferWorker.Companion.downLocation
|
||||
import com.yausername.youtubedl_android.DownloadProgressCallback
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import com.yausername.youtubedl_android.YoutubeDLResponse
|
||||
|
|
@ -37,13 +33,11 @@ import io.reactivex.Observable
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.jvm.functions.Function3
|
||||
|
||||
|
||||
class DownloaderService : Service() {
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ import com.deniscerri.ytdlnis.DownloaderService.LocalBinder
|
|||
import com.deniscerri.ytdlnis.database.DatabaseManager
|
||||
import com.deniscerri.ytdlnis.database.Video
|
||||
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
||||
import com.deniscerri.ytdlnis.page.DownloadsFragment
|
||||
import com.deniscerri.ytdlnis.page.HomeFragment
|
||||
import com.deniscerri.ytdlnis.page.MoreFragment
|
||||
import com.deniscerri.ytdlnis.page.settings.SettingsActivity
|
||||
import com.deniscerri.ytdlnis.ui.DownloadsFragment
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.MoreFragment
|
||||
import com.deniscerri.ytdlnis.ui.settings.SettingsActivity
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package com.deniscerri.ytdlnis.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.dao.HistoryDao
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class],
|
||||
version = 1,
|
||||
autoMigrations = []
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
abstract val resultDao : ResultDao
|
||||
abstract val historyDao : HistoryDao
|
||||
abstract val downloadDao : DownloadDao
|
||||
|
||||
companion object {
|
||||
//prevents multiple instances of db getting created at the same time
|
||||
@Volatile
|
||||
private var instance : DBManager? = null
|
||||
//if its not null return it, otherwise create db
|
||||
fun getInstance(context: Context) : DBManager {
|
||||
return instance ?: synchronized(this){
|
||||
val dbInstance = Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
DBManager::class.java,
|
||||
"YTDLnisDatabase"
|
||||
).build()
|
||||
instance = dbInstance
|
||||
dbInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
||||
@Dao
|
||||
interface DownloadDao {
|
||||
|
||||
@Query("SELECT * FROM downloads")
|
||||
fun getAllDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
|
||||
suspend fun getDownloadById(id: Int) : DownloadItem
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: DownloadItem)
|
||||
|
||||
@Query("DELETE FROM downloads")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Delete
|
||||
suspend fun delete(item: DownloadItem)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun update(item: DownloadItem)
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
||||
@Dao
|
||||
interface HistoryDao {
|
||||
|
||||
@Query("SELECT * FROM history WHERE title LIKE '%'||:query||'%' AND type LIKE '%'||:format||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
|
||||
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
|
||||
"CASE WHEN :sort = '' THEN id END DESC ")
|
||||
suspend fun getHistory(query : String, format : String, site : String, sort : String) : LiveData<List<HistoryItem>>
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
fun getAllHistory() : LiveData<List<HistoryItem>>
|
||||
|
||||
@Query("SELECT * FROM history WHERE id=:id LIMIT 1")
|
||||
suspend fun getHistoryItem(id: Int) : HistoryItem
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(item: HistoryItem)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(item: HistoryItem)
|
||||
|
||||
@Query("DELETE FROM history")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Query("DELETE FROM history WHERE id > (SELECT MIN(h.id) FROM history h WHERE h.url = history.url AND h.type = history.type)")
|
||||
suspend fun deleteDuplicates()
|
||||
|
||||
@Update
|
||||
suspend fun update(item: HistoryItem)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
||||
@Dao
|
||||
interface ResultDao {
|
||||
@Query("SELECT * FROM results")
|
||||
fun getResults() : LiveData<List<ResultItem>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(item: ResultItem)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun update(item: ResultItem)
|
||||
|
||||
@Query("DELETE FROM results")
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "downloads")
|
||||
data class DownloadItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
val duration: String,
|
||||
val thumb: String,
|
||||
val type: String,
|
||||
val downloadPath: String,
|
||||
val website: String
|
||||
)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "history")
|
||||
data class HistoryItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
val duration: String,
|
||||
val thumb: String,
|
||||
val type: String,
|
||||
val time: String,
|
||||
val downloadPath: String,
|
||||
val website: String
|
||||
//val isQueuedDownload: Int
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "results")
|
||||
data class ResultItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
val duration: String,
|
||||
val thumb: String,
|
||||
val website: String,
|
||||
val playlistTitle: String
|
||||
)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
||||
class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
|
||||
|
||||
suspend fun insert(item: DownloadItem){
|
||||
downloadDao.insert(item)
|
||||
}
|
||||
|
||||
suspend fun delete(item: DownloadItem){
|
||||
downloadDao.delete(item)
|
||||
}
|
||||
|
||||
suspend fun update(item: DownloadItem){
|
||||
downloadDao.update(item)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Transaction
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.dao.HistoryDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
||||
class HistoryRepository(private val historyDao: HistoryDao) {
|
||||
val allHistory : LiveData<List<HistoryItem>> = historyDao.getAllHistory()
|
||||
|
||||
suspend fun getItem(id: Int) : HistoryItem?{
|
||||
return historyDao.getHistoryItem(id)
|
||||
}
|
||||
|
||||
suspend fun insert(item: HistoryItem){
|
||||
historyDao.insert(item)
|
||||
}
|
||||
|
||||
suspend fun delete(item: HistoryItem){
|
||||
historyDao.delete(item)
|
||||
}
|
||||
|
||||
suspend fun deleteAll(){
|
||||
historyDao.deleteAll()
|
||||
}
|
||||
|
||||
suspend fun deleteDuplicates(){
|
||||
historyDao.deleteDuplicates()
|
||||
}
|
||||
|
||||
suspend fun update(item: HistoryItem){
|
||||
historyDao.update(item)
|
||||
}
|
||||
|
||||
suspend fun clearDeletedHistory(){
|
||||
val fileUtil = FileUtil()
|
||||
allHistory.value?.forEach { item ->
|
||||
if (!fileUtil.exists(item.downloadPath)){
|
||||
delete(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun checkDownloaded(){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
|
||||
class ResultRepository(private val resultDao: ResultDao) {
|
||||
val allResults : LiveData<List<ResultItem>> = resultDao.getResults()
|
||||
|
||||
suspend fun insert(items: List<ResultItem>){
|
||||
items.forEach {
|
||||
resultDao.insert(it)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteAll(){
|
||||
resultDao.deleteAll()
|
||||
}
|
||||
|
||||
suspend fun update(item: ResultItem){
|
||||
resultDao.update(item)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DownloadViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val repository : DownloadRepository
|
||||
private val allDownloads : LiveData<List<DownloadItem>>
|
||||
|
||||
init {
|
||||
val dao = DBManager.getInstance(application).downloadDao
|
||||
repository = DownloadRepository(dao)
|
||||
allDownloads = repository.allDownloads
|
||||
}
|
||||
|
||||
fun insertDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.insert(item)
|
||||
}
|
||||
|
||||
fun deleteDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.delete(item)
|
||||
}
|
||||
|
||||
fun updateDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.update(item);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HistoryViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val repository : HistoryRepository
|
||||
private val allHistory : LiveData<List<HistoryItem>>
|
||||
|
||||
init {
|
||||
val dao = DBManager.getInstance(application).historyDao
|
||||
repository = HistoryRepository(dao)
|
||||
allHistory = repository.allHistory
|
||||
}
|
||||
|
||||
fun insert(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.insert(item)
|
||||
}
|
||||
|
||||
fun delete(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.delete(item)
|
||||
}
|
||||
|
||||
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.deleteAll()
|
||||
}
|
||||
|
||||
fun deleteDuplicates() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.deleteDuplicates()
|
||||
}
|
||||
|
||||
fun update(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.update(item);
|
||||
}
|
||||
|
||||
fun clearDeleted() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.clearDeletedHistory()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.repository.ResultRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ResultViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val repository : ResultRepository
|
||||
private val allResults : LiveData<List<ResultItem>>
|
||||
|
||||
init {
|
||||
val dao = DBManager.getInstance(application).resultDao
|
||||
repository = ResultRepository(dao)
|
||||
allResults = repository.allResults
|
||||
}
|
||||
|
||||
fun insert(items: List<ResultItem>) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.insert(items)
|
||||
}
|
||||
|
||||
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.deleteAll()
|
||||
}
|
||||
|
||||
fun update(item: ResultItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.update(item);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,738 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.page;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.deniscerri.ytdlnis.MainActivity;
|
||||
import com.deniscerri.ytdlnis.R;
|
||||
import com.deniscerri.ytdlnis.adapter.DownloadsRecyclerViewAdapter;
|
||||
import com.deniscerri.ytdlnis.database.DatabaseManager;
|
||||
import com.deniscerri.ytdlnis.database.Video;
|
||||
import com.deniscerri.ytdlnis.service.DownloadInfo;
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener;
|
||||
import com.deniscerri.ytdlnis.util.FileUtil;
|
||||
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.BottomSheetDialog;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
public class DownloadsFragment extends Fragment implements DownloadsRecyclerViewAdapter.OnItemClickListener, View.OnClickListener, View.OnLongClickListener{
|
||||
private boolean downloading = false;
|
||||
private View fragmentView;
|
||||
private DatabaseManager databaseManager;
|
||||
Context context;
|
||||
Activity activity;
|
||||
MainActivity mainActivity;
|
||||
Context fragmentContext;
|
||||
private LayoutInflater layoutinflater;
|
||||
private ShimmerFrameLayout shimmerCards;
|
||||
private MaterialToolbar topAppBar;
|
||||
private RecyclerView recyclerView;
|
||||
private DownloadsRecyclerViewAdapter downloadsRecyclerViewAdapter;
|
||||
private BottomSheetDialog bottomSheet;
|
||||
private BottomSheetDialog sortSheet;
|
||||
private Handler uiHandler;
|
||||
private RelativeLayout no_results;
|
||||
private LinearLayout selectionChips;
|
||||
private ChipGroup websiteGroup;
|
||||
private ArrayList<Video> downloadsObjects;
|
||||
public ArrayList<Video> selectedObjects;
|
||||
private LinearProgressIndicator progressBar;
|
||||
private ExtendedFloatingActionButton deleteFab;
|
||||
private FileUtil fileUtil;
|
||||
private String format = "";
|
||||
private String website = "";
|
||||
private String sort = "DESC";
|
||||
private String searchQuery = "";
|
||||
|
||||
private static final String TAG = "downloadsFragment";
|
||||
|
||||
|
||||
public IDownloaderListener listener = new IDownloaderListener() {
|
||||
|
||||
public void onDownloadStart(DownloadInfo downloadInfo) {
|
||||
try{
|
||||
if(downloadInfo != null){
|
||||
Video v = downloadInfo.getVideo();
|
||||
progressBar = fragmentView.findViewWithTag(v.getURL()+v.getDownloadedType()+"##progress");
|
||||
}
|
||||
}catch(Exception ignored){}
|
||||
downloading = true;
|
||||
}
|
||||
|
||||
public void onDownloadProgress(DownloadInfo info) {
|
||||
activity.runOnUiThread(() -> {
|
||||
try{
|
||||
int progress = info.getProgress();
|
||||
Video v = info.getVideo();
|
||||
if (progress > 0) {
|
||||
progressBar = fragmentView.findViewWithTag(v.getURL()+v.getDownloadedType()+"##progress");
|
||||
progressBar.setProgressCompat(progress, true);
|
||||
}
|
||||
}catch(Exception ignored){
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onDownloadError(DownloadInfo info){
|
||||
try{
|
||||
Video item = info.getVideo();
|
||||
Log.e(TAG, item.toString());
|
||||
String url = item.getURL();
|
||||
String type = info.getDownloadType();
|
||||
Video v = findVideo(url, type);
|
||||
Log.e(TAG, v.toString());
|
||||
databaseManager = new DatabaseManager(context);
|
||||
databaseManager.clearHistoryItem(v, false);
|
||||
int position = downloadsObjects.indexOf(v);
|
||||
downloadsRecyclerViewAdapter.notifyItemRemoved(position);
|
||||
downloadsObjects.remove(v);
|
||||
|
||||
if (downloadsObjects.isEmpty()) initCards();
|
||||
downloading = false;
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadEnd(DownloadInfo downloadInfo) {
|
||||
Video item = downloadInfo.getVideo();
|
||||
String url = item.getURL();
|
||||
String type = downloadInfo.getDownloadType();
|
||||
String path = downloadInfo.getDownloadPath();
|
||||
item = findVideo(url, type);
|
||||
int index = downloadsObjects.indexOf(item);
|
||||
try{
|
||||
item.setDownloadedType(type);
|
||||
item.setDownloadPath(path);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
Date date = new Date();
|
||||
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 time = formatter.format(date);
|
||||
String downloadedTime = day + " " + month + " " + year + " " + time;
|
||||
|
||||
String downloadPath = "";
|
||||
try{
|
||||
downloadPath = fileUtil.scanMedia(item, context);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
databaseManager = new DatabaseManager(context);
|
||||
//TODO observe file transfer worker here and then update, but first you need to turn this to kotlin and implement proper mvvm
|
||||
try {
|
||||
item.setDownloadedTime(downloadedTime);
|
||||
item.setDownloadPath(downloadPath);
|
||||
item.setQueuedDownload(false);
|
||||
databaseManager.updateHistoryItem(item);
|
||||
databaseManager.close();
|
||||
downloadsRecyclerViewAdapter.notifyItemChanged(index);
|
||||
} catch (Exception ignored) {}
|
||||
downloading = false;
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadCancel(DownloadInfo info) {
|
||||
Video v = info.getVideo();
|
||||
v = findVideo(v.getURL(), v.getDownloadedType());
|
||||
try {
|
||||
databaseManager = new DatabaseManager(context);
|
||||
databaseManager.clearHistoryItem(v,false);
|
||||
databaseManager.close();
|
||||
downloadsRecyclerViewAdapter.notifyItemRemoved(downloadsObjects.indexOf(v));
|
||||
downloadsObjects.remove(v);
|
||||
if (downloadsObjects.isEmpty()) initCards();
|
||||
downloading = false;
|
||||
}catch (Exception ignored){}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadCancelAll(DownloadInfo downloadInfo){
|
||||
try {
|
||||
databaseManager = new DatabaseManager(context);
|
||||
databaseManager.clearDownloadingHistory();
|
||||
databaseManager.close();
|
||||
initCards();
|
||||
downloading = false;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadServiceEnd() {}
|
||||
};
|
||||
|
||||
public void setDownloading(boolean d){
|
||||
downloading = d;
|
||||
}
|
||||
|
||||
|
||||
public DownloadsFragment() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static DownloadsFragment newInstance() {
|
||||
DownloadsFragment fragment = new DownloadsFragment();
|
||||
Bundle args = new Bundle();
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
fragmentView = inflater.inflate(R.layout.fragment_downloads, container, false);
|
||||
context = fragmentView.getContext().getApplicationContext();
|
||||
activity = getActivity();
|
||||
mainActivity = (MainActivity) activity;
|
||||
fragmentContext = fragmentView.getContext();
|
||||
layoutinflater = LayoutInflater.from(context);
|
||||
shimmerCards = fragmentView.findViewById(R.id.shimmer_downloads_framelayout);
|
||||
topAppBar = fragmentView.findViewById(R.id.downloads_toolbar);
|
||||
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);
|
||||
fileUtil = new FileUtil();
|
||||
|
||||
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);
|
||||
downloadsRecyclerViewAdapter = new DownloadsRecyclerViewAdapter(downloadsObjects, this, activity);
|
||||
recyclerView.setAdapter(downloadsRecyclerViewAdapter);
|
||||
recyclerView.setNestedScrollingEnabled(false);
|
||||
|
||||
initMenu();
|
||||
initChips();
|
||||
initCards();
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
public void initCards(){
|
||||
shimmerCards.startShimmer();
|
||||
shimmerCards.setVisibility(View.VISIBLE);
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
no_results.setVisibility(View.GONE);
|
||||
selectionChips.setVisibility(View.VISIBLE);
|
||||
databaseManager = new DatabaseManager(context);
|
||||
try{
|
||||
Thread thread = new Thread(() -> {
|
||||
if (!downloading) databaseManager.clearDownloadingHistory();
|
||||
downloadsObjects = databaseManager.getHistory("", format,website,sort);
|
||||
uiHandler.post(() -> {
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
shimmerCards.stopShimmer();
|
||||
shimmerCards.setVisibility(View.GONE);
|
||||
updateWebsiteChips();
|
||||
});
|
||||
|
||||
if(downloadsObjects.size() == 0){
|
||||
uiHandler.post(() -> {
|
||||
no_results.setVisibility(View.VISIBLE);
|
||||
selectionChips.setVisibility(View.GONE);
|
||||
websiteGroup.removeAllViews();
|
||||
});
|
||||
}
|
||||
databaseManager.close();
|
||||
});
|
||||
thread.start();
|
||||
}catch(Exception e){
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void scrollToTop(){
|
||||
recyclerView.scrollToPosition(0);
|
||||
new Handler(Looper.getMainLooper()).post(() -> ((AppBarLayout) topAppBar.getParent()).setExpanded(true, true));
|
||||
}
|
||||
|
||||
private void initMenu(){
|
||||
MenuItem.OnActionExpandListener onActionExpandListener = new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem menuItem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem menuItem) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
MaterialToolbar toolbar = fragmentView.findViewById(R.id.downloads_toolbar);
|
||||
|
||||
topAppBar.getMenu().findItem(R.id.search_downloads).setOnActionExpandListener(onActionExpandListener);
|
||||
SearchView searchView = (SearchView) topAppBar.getMenu().findItem(R.id.search_downloads).getActionView();
|
||||
searchView.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
searchView.setQueryHint(getString(R.string.search_history_hint));
|
||||
|
||||
databaseManager = new DatabaseManager(context);
|
||||
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
searchQuery = query;
|
||||
topAppBar.getMenu().findItem(R.id.search_downloads).collapseActionView();
|
||||
downloadsObjects = databaseManager.getHistory(query, format,website,sort);
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
|
||||
if(downloadsObjects.size() == 0) {
|
||||
no_results.setVisibility(View.VISIBLE);
|
||||
selectionChips.setVisibility(View.GONE);
|
||||
websiteGroup.removeAllViews();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
searchQuery = newText;
|
||||
downloadsObjects = databaseManager.getHistory(newText, format,website,sort);
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
|
||||
if (downloadsObjects.size() == 0) {
|
||||
no_results.setVisibility(View.VISIBLE);
|
||||
selectionChips.setVisibility(View.GONE);
|
||||
}else{
|
||||
no_results.setVisibility(View.GONE);
|
||||
selectionChips.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
topAppBar.setOnClickListener(view -> scrollToTop());
|
||||
|
||||
topAppBar.setOnMenuItemClickListener((MenuItem m) -> {
|
||||
int itemID = m.getItemId();
|
||||
if(itemID == R.id.remove_downloads) {
|
||||
if (downloadsObjects.size() == 0) {
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
|
||||
delete_dialog.setTitle(getString(R.string.confirm_delete_history));
|
||||
delete_dialog.setMessage(getString(R.string.confirm_delete_history_desc));
|
||||
delete_dialog.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
|
||||
dialogInterface.cancel();
|
||||
});
|
||||
delete_dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
|
||||
databaseManager.clearHistory();
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsObjects.clear();
|
||||
no_results.setVisibility(View.VISIBLE);
|
||||
selectionChips.setVisibility(View.GONE);
|
||||
websiteGroup.removeAllViews();
|
||||
});
|
||||
delete_dialog.show();
|
||||
}else if(itemID == R.id.remove_deleted_downloads){
|
||||
if (downloadsObjects.size() == 0) {
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
|
||||
delete_dialog.setTitle(getString(R.string.confirm_delete_history));
|
||||
delete_dialog.setMessage(getString(R.string.confirm_delete_history_deleted_desc));
|
||||
delete_dialog.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
|
||||
dialogInterface.cancel();
|
||||
});
|
||||
delete_dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
|
||||
databaseManager.clearDeletedHistory();
|
||||
initCards();
|
||||
});
|
||||
delete_dialog.show();
|
||||
}else if (itemID == R.id.remove_duplicates){
|
||||
if (downloadsObjects.size() == 0) {
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
|
||||
delete_dialog.setTitle(getString(R.string.confirm_delete_history));
|
||||
delete_dialog.setMessage(getString(R.string.confirm_delete_history_duplicates_desc));
|
||||
delete_dialog.setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
|
||||
dialogInterface.cancel();
|
||||
});
|
||||
delete_dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
|
||||
databaseManager.clearDuplicateHistory();
|
||||
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 true;
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder delete_dialog = new 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, i) -> {
|
||||
dialogInterface.cancel();
|
||||
});
|
||||
delete_dialog.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
|
||||
databaseManager.clearDownloadingHistory();
|
||||
mainActivity.cancelDownloadService();
|
||||
initCards();
|
||||
});
|
||||
delete_dialog.show();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void initChips(){
|
||||
//sort and history/downloading switch
|
||||
Chip sortChip = fragmentView.findViewById(R.id.sort_chip);
|
||||
sortChip.setOnClickListener(view -> {
|
||||
sortSheet = new BottomSheetDialog(fragmentContext);
|
||||
sortSheet.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
sortSheet.setContentView(R.layout.downloads_sort_sheet);
|
||||
|
||||
TextView newest = sortSheet.findViewById(R.id.newest);
|
||||
TextView oldest = sortSheet.findViewById(R.id.oldest);
|
||||
|
||||
newest.setOnClickListener(view1 -> {
|
||||
sort = "DESC";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery, format,website,sort);
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
sortSheet.cancel();
|
||||
});
|
||||
|
||||
oldest.setOnClickListener(view1 -> {
|
||||
sort = "ASC";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery, format,website,sort);
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
sortSheet.cancel();
|
||||
});
|
||||
|
||||
TextView cancel = sortSheet.findViewById(R.id.cancel);
|
||||
cancel.setOnClickListener(view1 -> {
|
||||
sortSheet.cancel();
|
||||
});
|
||||
|
||||
sortSheet.show();
|
||||
sortSheet.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
});
|
||||
|
||||
//format
|
||||
Chip audio = fragmentView.findViewById(R.id.audio_chip);
|
||||
audio.setOnClickListener(view -> {
|
||||
if (audio.isChecked()) {
|
||||
format = "audio";
|
||||
if (recyclerView.getVisibility() == View.GONE){
|
||||
|
||||
}
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
audio.setChecked(true);
|
||||
}else {
|
||||
format = "";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
audio.setChecked(false);
|
||||
}
|
||||
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
});
|
||||
|
||||
Chip video = fragmentView.findViewById(R.id.video_chip);
|
||||
video.setOnClickListener(view -> {
|
||||
if (video.isChecked()) {
|
||||
format = "video";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
video.setChecked(true);
|
||||
}else {
|
||||
format = "";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
video.setChecked(false);
|
||||
}
|
||||
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void updateWebsiteChips(){
|
||||
websiteGroup.removeAllViews();
|
||||
|
||||
ArrayList<String> websites = downloadsRecyclerViewAdapter.getWebsites();
|
||||
for (int i = 0; i < websites.size(); i++){
|
||||
String w = websites.get(i);
|
||||
Chip tmp = (Chip) layoutinflater.inflate(R.layout.filter_chip, websiteGroup, false);
|
||||
tmp.setText(w);
|
||||
tmp.setId(i);
|
||||
tmp.setOnClickListener(view -> {
|
||||
if (tmp.isChecked()){
|
||||
website = (String) tmp.getText();
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
websiteGroup.check(view.getId());
|
||||
}else{
|
||||
website = "";
|
||||
downloadsObjects = databaseManager.getHistory(searchQuery,format,website,sort);
|
||||
websiteGroup.clearCheck();
|
||||
}
|
||||
downloadsRecyclerViewAdapter.clear();
|
||||
downloadsRecyclerViewAdapter.add(downloadsObjects);
|
||||
});
|
||||
websiteGroup.addView(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
if(id == R.id.bottomsheet_remove_button){
|
||||
removedownloadsItem((Integer) v.getTag());
|
||||
}else if(id == R.id.bottom_sheet_link){
|
||||
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};
|
||||
databaseManager = new DatabaseManager(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.remove(position);
|
||||
databaseManager.clearHistoryItem(v, delete_file[0]);
|
||||
}
|
||||
updateWebsiteChips();
|
||||
databaseManager.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};
|
||||
databaseManager = new DatabaseManager(context);
|
||||
|
||||
Video v = downloadsObjects.get(position);
|
||||
MaterialAlertDialogBuilder delete_dialog = new MaterialAlertDialogBuilder(fragmentContext);
|
||||
delete_dialog.setTitle(getString(R.string.you_are_going_to_delete) + " \""+v.getTitle()+"\"!");
|
||||
delete_dialog.setMultiChoiceItems(new String[]{getString(R.string.delete_file_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) -> {
|
||||
downloadsObjects.remove(position);
|
||||
downloadsRecyclerViewAdapter.remove(position);
|
||||
updateWebsiteChips();
|
||||
databaseManager.clearHistoryItem(v, delete_file[0]);
|
||||
databaseManager.close();
|
||||
|
||||
if(downloadsObjects.size() == 0){
|
||||
uiHandler.post(() -> {
|
||||
no_results.setVisibility(View.VISIBLE);
|
||||
selectionChips.setVisibility(View.GONE);
|
||||
websiteGroup.removeAllViews();
|
||||
});
|
||||
}
|
||||
});
|
||||
delete_dialog.show();
|
||||
}
|
||||
|
||||
private void copyLinkToClipBoard(int position){
|
||||
String url = downloadsObjects.get(position).getURL();
|
||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData 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 void openLinkIntent(int position){
|
||||
String url =downloadsObjects.get(position).getURL();
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
if(bottomSheet != null) bottomSheet.hide();
|
||||
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);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCardClick(int position, boolean isFilePresent) {
|
||||
bottomSheet = new BottomSheetDialog(fragmentContext);
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
bottomSheet.setContentView(R.layout.downloads_bottom_sheet);
|
||||
Video video = downloadsObjects.get(position);
|
||||
|
||||
TextView title = bottomSheet.findViewById(R.id.bottom_sheet_title);
|
||||
title.setText(video.getTitle());
|
||||
|
||||
TextView author = bottomSheet.findViewById(R.id.bottom_sheet_author);
|
||||
author.setText(video.getAuthor());
|
||||
|
||||
Button link = bottomSheet.findViewById(R.id.bottom_sheet_link);
|
||||
String url = video.getURL();
|
||||
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 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);
|
||||
try {
|
||||
mainActivity.removeItemFromDownloadQueue(vid, vid.getDownloadedType());
|
||||
}catch (Exception e){
|
||||
DownloadInfo info = new DownloadInfo();
|
||||
info.setVideo(vid);
|
||||
info.setDownloadType(vid.getDownloadedType());
|
||||
listener.onDownloadCancel(info);
|
||||
}
|
||||
}
|
||||
|
||||
public Video findVideo(String url, String type) {
|
||||
for (int i = 0; i < downloadsObjects.size(); i++) {
|
||||
Video v = downloadsObjects.get(i);
|
||||
if ((v.getURL()).equals(url) && v.getDownloadedType().equals(type) && v.isQueuedDownload()) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.page;
|
||||
package com.deniscerri.ytdlnis.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ComponentName;
|
||||
|
|
@ -19,7 +19,6 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
import androidx.core.app.ActivityCompat;
|
||||
import com.deniscerri.ytdlnis.R;
|
||||
import com.deniscerri.ytdlnis.DownloaderService;
|
||||
import com.deniscerri.ytdlnis.database.Video;
|
||||
import com.deniscerri.ytdlnis.service.DownloadInfo;
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener;
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService;
|
||||
|
|
@ -27,7 +26,6 @@ import com.deniscerri.ytdlnis.util.NotificationUtil;
|
|||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CustomCommandActivity extends AppCompatActivity {
|
||||
554
app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadsFragment.kt
Normal file
554
app/src/main/java/com/deniscerri/ytdlnis/ui/DownloadsFragment.kt
Normal file
|
|
@ -0,0 +1,554 @@
|
|||
package com.deniscerri.ytdlnis.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.widget.*
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.DownloadsRecyclerViewAdapter
|
||||
import com.deniscerri.ytdlnis.database.DatabaseManager
|
||||
import com.deniscerri.ytdlnis.database.Video
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||
import com.deniscerri.ytdlnis.service.DownloadInfo
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
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.BottomSheetDialog
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
class DownloadsFragment : Fragment(), DownloadsRecyclerViewAdapter.OnItemClickListener,
|
||||
View.OnClickListener, OnLongClickListener {
|
||||
private lateinit var historyViewModel : HistoryViewModel
|
||||
|
||||
private var downloading = false
|
||||
private var fragmentView: View? = null
|
||||
private var databaseManager: DatabaseManager? = null
|
||||
var activity: Activity? = null
|
||||
var mainActivity: MainActivity? = null
|
||||
var fragmentContext: Context? = null
|
||||
private var layoutinflater: LayoutInflater? = null
|
||||
private var shimmerCards: ShimmerFrameLayout? = null
|
||||
private var topAppBar: MaterialToolbar? = null
|
||||
private var recyclerView: RecyclerView? = null
|
||||
private var downloadsRecyclerViewAdapter: DownloadsRecyclerViewAdapter? = null
|
||||
private var bottomSheet: BottomSheetDialog? = null
|
||||
private var sortSheet: BottomSheetDialog? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var no_results: RelativeLayout? = null
|
||||
private var selectionChips: LinearLayout? = null
|
||||
private var websiteGroup: ChipGroup? = null
|
||||
private var downloadsObjects: ArrayList<Video?>? = null
|
||||
var selectedObjects: ArrayList<Video?>? = null
|
||||
private var progressBar: LinearProgressIndicator? = null
|
||||
private var deleteFab: ExtendedFloatingActionButton? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var format = ""
|
||||
private var website = ""
|
||||
private var sort = "DESC"
|
||||
private var searchQuery = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||
activity = getActivity()
|
||||
mainActivity = activity as MainActivity?
|
||||
fragmentContext = context?.applicationContext
|
||||
layoutinflater = LayoutInflater.from(context)
|
||||
|
||||
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||
|
||||
|
||||
shimmerCards = this.view?.findViewById(R.id.shimmer_downloads_framelayout)
|
||||
topAppBar = this.view?.findViewById(R.id.downloads_toolbar)
|
||||
no_results = this.view?.findViewById(R.id.downloads_no_results)
|
||||
selectionChips = this.view?.findViewById(R.id.downloads_selection_chips)
|
||||
websiteGroup = this.view?.findViewById(R.id.website_chip_group)
|
||||
deleteFab = this.view?.findViewById(R.id.delete_selected_fab)
|
||||
fileUtil = FileUtil()
|
||||
deleteFab?.tag = "deleteSelected"
|
||||
deleteFab?.setOnClickListener(this)
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
downloadsObjects = ArrayList()
|
||||
selectedObjects = ArrayList()
|
||||
downloading = mainActivity!!.isDownloadServiceRunning()
|
||||
recyclerView = this.view?.findViewById(R.id.recycler_view_downloads)
|
||||
downloadsRecyclerViewAdapter =
|
||||
DownloadsRecyclerViewAdapter(downloadsObjects, this, activity)
|
||||
recyclerView?.adapter = downloadsRecyclerViewAdapter
|
||||
recyclerView?.isNestedScrollingEnabled = false
|
||||
initMenu()
|
||||
initChips()
|
||||
initCards()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
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() {
|
||||
recyclerView!!.scrollToPosition(0)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
(topAppBar!!.parent as AppBarLayout).setExpanded(
|
||||
true,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initMenu() {
|
||||
val onActionExpandListener: MenuItem.OnActionExpandListener =
|
||||
object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
val toolbar = fragmentView!!.findViewById<MaterialToolbar>(R.id.downloads_toolbar)
|
||||
topAppBar!!.menu.findItem(R.id.search_downloads)
|
||||
.setOnActionExpandListener(onActionExpandListener)
|
||||
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 {
|
||||
searchQuery = query
|
||||
topAppBar!!.menu.findItem(R.id.search_downloads).collapseActionView()
|
||||
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
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
searchQuery = 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
|
||||
}
|
||||
})
|
||||
topAppBar!!.setOnClickListener { view: View? -> scrollToTop() }
|
||||
topAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
|
||||
val itemID = m.itemId
|
||||
if (itemID == R.id.remove_downloads) {
|
||||
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_history_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!!.clearHistory()
|
||||
downloadsRecyclerViewAdapter!!.clear()
|
||||
downloadsObjects!!.clear()
|
||||
no_results!!.visibility = View.VISIBLE
|
||||
selectionChips!!.visibility = View.GONE
|
||||
websiteGroup!!.removeAllViews()
|
||||
}
|
||||
delete_dialog.show()
|
||||
} else if (itemID == R.id.remove_deleted_downloads) {
|
||||
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_history_deleted_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!!.clearDeletedHistory()
|
||||
initCards()
|
||||
}
|
||||
delete_dialog.show()
|
||||
} else if (itemID == R.id.remove_duplicates) {
|
||||
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_history_duplicates_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!!.clearDuplicateHistory()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
private fun initChips() {
|
||||
//sort and history/downloading switch
|
||||
val sortChip = fragmentView!!.findViewById<Chip>(R.id.sort_chip)
|
||||
sortChip.setOnClickListener { view: View? ->
|
||||
sortSheet = BottomSheetDialog(fragmentContext!!)
|
||||
sortSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
sortSheet!!.setContentView(R.layout.downloads_sort_sheet)
|
||||
val newest = sortSheet!!.findViewById<TextView>(R.id.newest)
|
||||
val oldest = sortSheet!!.findViewById<TextView>(R.id.oldest)
|
||||
newest!!.setOnClickListener { view1: View? ->
|
||||
sort = "DESC"
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
downloadsRecyclerViewAdapter!!.clear()
|
||||
downloadsRecyclerViewAdapter!!.add(downloadsObjects)
|
||||
sortSheet!!.cancel()
|
||||
}
|
||||
oldest!!.setOnClickListener { view1: View? ->
|
||||
sort = "ASC"
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
downloadsRecyclerViewAdapter!!.clear()
|
||||
downloadsRecyclerViewAdapter!!.add(downloadsObjects)
|
||||
sortSheet!!.cancel()
|
||||
}
|
||||
val cancel = sortSheet!!.findViewById<TextView>(R.id.cancel)
|
||||
cancel!!.setOnClickListener { view1: View? -> sortSheet!!.cancel() }
|
||||
sortSheet!!.show()
|
||||
sortSheet!!.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
//format
|
||||
val audio = fragmentView!!.findViewById<Chip>(R.id.audio_chip)
|
||||
audio.setOnClickListener { view: View? ->
|
||||
if (audio.isChecked) {
|
||||
format = "audio"
|
||||
if (recyclerView!!.visibility == View.GONE) {
|
||||
}
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
audio.isChecked = true
|
||||
} else {
|
||||
format = ""
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
audio.isChecked = false
|
||||
}
|
||||
downloadsRecyclerViewAdapter!!.clear()
|
||||
downloadsRecyclerViewAdapter!!.add(downloadsObjects)
|
||||
}
|
||||
val video = fragmentView!!.findViewById<Chip>(R.id.video_chip)
|
||||
video.setOnClickListener { view: View? ->
|
||||
if (video.isChecked) {
|
||||
format = "video"
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
video.isChecked = true
|
||||
} else {
|
||||
format = ""
|
||||
downloadsObjects = databaseManager!!.getHistory(searchQuery, format, website, sort)
|
||||
video.isChecked = false
|
||||
}
|
||||
downloadsRecyclerViewAdapter!!.clear()
|
||||
downloadsRecyclerViewAdapter!!.add(downloadsObjects)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWebsiteChips() {
|
||||
websiteGroup!!.removeAllViews()
|
||||
val websites = downloadsRecyclerViewAdapter!!.websites
|
||||
for (i in websites.indices) {
|
||||
val w = websites[i]
|
||||
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
|
||||
tmp.text = w
|
||||
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) {
|
||||
val id = v.id
|
||||
if (id == R.id.bottomsheet_remove_button) {
|
||||
removedownloadsItem(v.tag as Int)
|
||||
} else if (id == R.id.bottom_sheet_link) {
|
||||
openLinkIntent(v.tag as Int)
|
||||
} else if (id == R.id.bottomsheet_open_file_button) {
|
||||
openFileIntent(v.tag as Int)
|
||||
} else if (id == R.id.delete_selected_fab) {
|
||||
removeSelectedItems()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
val id = v.id
|
||||
if (id == R.id.bottom_sheet_link) {
|
||||
copyLinkToClipBoard(v.tag as Int)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun removeSelectedItems() {
|
||||
if (bottomSheet != null) bottomSheet!!.hide()
|
||||
val delete_file = booleanArrayOf(false)
|
||||
databaseManager = DatabaseManager(context)
|
||||
val delete_dialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
delete_dialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
delete_dialog.setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.delete_files_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 ->
|
||||
for (j in selectedObjects!!.indices) {
|
||||
val v = selectedObjects!![j]
|
||||
val position = downloadsObjects!!.indexOf(v)
|
||||
downloadsObjects!!.remove(v)
|
||||
downloadsRecyclerViewAdapter!!.remove(position)
|
||||
databaseManager!!.clearHistoryItem(v, delete_file[0])
|
||||
}
|
||||
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) {
|
||||
val downloadPath = downloadsObjects!![position]!!.downloadPath
|
||||
val file = File(downloadPath)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
fragmentContext!!,
|
||||
fragmentContext!!.packageName + ".fileprovider",
|
||||
file
|
||||
)
|
||||
val mime = mainActivity!!.contentResolver.getType(uri)
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.setDataAndType(uri, mime)
|
||||
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivity(i)
|
||||
}
|
||||
|
||||
override fun onCardClick(position: Int, isFilePresent: Boolean) {
|
||||
bottomSheet = BottomSheetDialog(fragmentContext!!)
|
||||
bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet!!.setContentView(R.layout.downloads_bottom_sheet)
|
||||
val video = downloadsObjects!![position]
|
||||
val title = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_title)
|
||||
title!!.text = video!!.title
|
||||
val author = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_author)
|
||||
author!!.text = video.author
|
||||
val link = bottomSheet!!.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
val url = video.getURL()
|
||||
link!!.text = url
|
||||
link.tag = position
|
||||
link.setOnClickListener(this)
|
||||
link.setOnLongClickListener(this)
|
||||
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
remove!!.tag = position
|
||||
remove.setOnClickListener(this)
|
||||
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
||||
openFile!!.tag = position
|
||||
openFile.setOnClickListener(this)
|
||||
if (!isFilePresent) openFile.visibility = View.GONE
|
||||
bottomSheet!!.show()
|
||||
bottomSheet!!.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCardSelect(position: Int, add: Boolean) {
|
||||
val video = downloadsObjects!![position]
|
||||
if (add) selectedObjects!!.add(video) else selectedObjects!!.remove(video)
|
||||
if (selectedObjects!!.size > 1) {
|
||||
deleteFab!!.visibility = View.VISIBLE
|
||||
} else {
|
||||
deleteFab!!.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onButtonClick(position: Int) {
|
||||
val vid = downloadsObjects!![position]
|
||||
try {
|
||||
mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType)
|
||||
} catch (e: Exception) {
|
||||
val info = DownloadInfo()
|
||||
info.video = vid
|
||||
info.downloadType = vid!!.downloadedType
|
||||
}
|
||||
}
|
||||
|
||||
fun findVideo(url: String, type: String): Video? {
|
||||
for (i in downloadsObjects!!.indices) {
|
||||
val v = downloadsObjects!![i]
|
||||
if (v!!.getURL() == url && v.downloadedType == type && v.isQueuedDownload) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "downloadsFragment"
|
||||
fun newInstance(): DownloadsFragment {
|
||||
val fragment = DownloadsFragment()
|
||||
val args = Bundle()
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.page;
|
||||
package com.deniscerri.ytdlnis.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.page;
|
||||
package com.deniscerri.ytdlnis.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.page.settings;
|
||||
package com.deniscerri.ytdlnis.ui.settings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.page.settings
|
||||
package com.deniscerri.ytdlnis.ui.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.deniscerri.ytdlnis.work;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.ForegroundInfo;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import com.deniscerri.ytdlnis.MainActivity;
|
||||
import com.deniscerri.ytdlnis.database.Video;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.random.Random;
|
||||
|
||||
public class DownloadWorker extends Worker {
|
||||
private Context context;
|
||||
private WorkerParameters workerParams;
|
||||
public DownloadWorker(
|
||||
@NonNull Context appContext,
|
||||
@NonNull WorkerParameters workerParams) {
|
||||
super(appContext, workerParams);
|
||||
this.context = appContext;
|
||||
this.workerParams = workerParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
//TODO
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import androidx.work.CoroutineWorker
|
|||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.page.CustomCommandActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import java.io.File
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.deniscerri.ytdlnis.page.CustomCommandActivity">
|
||||
tools:context="com.deniscerri.ytdlnis.ui.CustomCommandActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/custom_command_frame_layout"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.deniscerri.ytdlnis.page.settings.SettingsActivity">
|
||||
tools:context="com.deniscerri.ytdlnis.ui.settings.SettingsActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settings_frame_layout"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ buildscript {
|
|||
composeVer = "1.3.2"
|
||||
kotlinVer = "1.7.20"
|
||||
coroutineVer = "1.6.4"
|
||||
retrofitVer = "2.9.0"
|
||||
kodeinVer = "7.16.0"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ dependencyResolutionManagement {
|
|||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url "https://dl.bintray.com/kodein-framework/Kodein-DI" }
|
||||
}
|
||||
}
|
||||
rootProject.name = "YTDLnis"
|
||||
|
|
|
|||
Loading…
Reference in a new issue