mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	download stuff
This commit is contained in:
		
							parent
							
								
									062d7feff9
								
							
						
					
					
						commit
						57828527aa
					
				
					 11 changed files with 281 additions and 65 deletions
				
			
		|  | @ -50,18 +50,22 @@ object UIHelper { | |||
|     val Float.toDp: Float get() = (this / Resources.getSystem().displayMetrics.density) | ||||
| 
 | ||||
|     fun Activity.checkWrite(): Boolean { | ||||
|         return (ContextCompat.checkSelfPermission(this, | ||||
|             Manifest.permission.WRITE_EXTERNAL_STORAGE) | ||||
|         return (ContextCompat.checkSelfPermission( | ||||
|             this, | ||||
|             Manifest.permission.WRITE_EXTERNAL_STORAGE | ||||
|         ) | ||||
|                 == PackageManager.PERMISSION_GRANTED) | ||||
|     } | ||||
| 
 | ||||
|     fun Activity.requestRW() { | ||||
|         ActivityCompat.requestPermissions(this, | ||||
|         ActivityCompat.requestPermissions( | ||||
|             this, | ||||
|             arrayOf( | ||||
|                 Manifest.permission.WRITE_EXTERNAL_STORAGE, | ||||
|                 Manifest.permission.READ_EXTERNAL_STORAGE | ||||
|             ), | ||||
|             1337) | ||||
|             1337 | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @ColorInt | ||||
|  | @ -141,6 +145,7 @@ object UIHelper { | |||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private var currentAudioFocusRequest: AudioFocusRequest? = null | ||||
|     private var currentAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null | ||||
|     var onAudioFocusEvent = Event<Boolean>() | ||||
|  | @ -246,18 +251,19 @@ object UIHelper { | |||
|         // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY | ||||
|         window.decorView.systemUiVisibility = ( | ||||
|                 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | ||||
|                 // Set the content to appear under the system bars so that the | ||||
|                 // content doesn't resize when the system bars hide and show. | ||||
|                 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE | ||||
|                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | ||||
|                 or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | ||||
|                 // Hide the nav bar and status bar | ||||
|                 or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | ||||
|                 or View.SYSTEM_UI_FLAG_FULLSCREEN | ||||
|                         // Set the content to appear under the system bars so that the | ||||
|                         // content doesn't resize when the system bars hide and show. | ||||
|                         or View.SYSTEM_UI_FLAG_LAYOUT_STABLE | ||||
|                         or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | ||||
|                         or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | ||||
|                         // Hide the nav bar and status bar | ||||
|                         or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | ||||
|                         or View.SYSTEM_UI_FLAG_FULLSCREEN | ||||
|                 //  or View.SYSTEM_UI_FLAG_LOW_PROFILE | ||||
|                 ) | ||||
|         // window.addFlags(View.KEEP_SCREEN_ON) | ||||
|     } | ||||
| 
 | ||||
|     fun FragmentActivity.popCurrentPage() { | ||||
|         val currentFragment = supportFragmentManager.fragments.lastOrNull { | ||||
|             it.isVisible | ||||
|  | @ -363,10 +369,11 @@ object UIHelper { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /**id, icon, stringRes */ | ||||
|     @SuppressLint("RestrictedApi") | ||||
|     inline fun View.popupMenu( | ||||
|     fun View.popupMenu( | ||||
|         items: List<Triple<Int, Int, Int>>, | ||||
|         noinline onMenuItemClick: MenuItem.() -> Unit, | ||||
|         onMenuItemClick: MenuItem.() -> Unit, | ||||
|     ): PopupMenu { | ||||
|         val ctw = ContextThemeWrapper(context, R.style.PopupMenu) | ||||
|         val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0) | ||||
|  | @ -386,9 +393,11 @@ object UIHelper { | |||
|         return popup | ||||
|     } | ||||
| 
 | ||||
|     inline fun View.popupMenuNoIcons( | ||||
|     /**id, stringRes */ | ||||
|     @SuppressLint("RestrictedApi") | ||||
|     fun View.popupMenuNoIcons( | ||||
|         items: List<Pair<Int, Int>>, | ||||
|         noinline onMenuItemClick: MenuItem.() -> Unit, | ||||
|         onMenuItemClick: MenuItem.() -> Unit, | ||||
|     ): PopupMenu { | ||||
|         val ctw = ContextThemeWrapper(context, R.style.PopupMenu) | ||||
|         val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0) | ||||
|  | @ -408,15 +417,17 @@ object UIHelper { | |||
|         return popup | ||||
|     } | ||||
| 
 | ||||
|     inline fun View.popupMenuNoIconsAndNoStringres( | ||||
|     /**id, string */ | ||||
|     @SuppressLint("RestrictedApi") | ||||
|     fun View.popupMenuNoIconsAndNoStringres( | ||||
|         items: List<Pair<Int, String>>, | ||||
|         noinline onMenuItemClick: MenuItem.() -> Unit, | ||||
|         onMenuItemClick: MenuItem.() -> Unit, | ||||
|     ): PopupMenu { | ||||
|         val ctw = ContextThemeWrapper(context, R.style.PopupMenu) | ||||
|         val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0) | ||||
| 
 | ||||
|         items.forEach { (id, stringRes) -> | ||||
|             popup.menu.add(0, id, 0, stringRes) | ||||
|         items.forEach { (id, string) -> | ||||
|             popup.menu.add(0, id, 0, string) | ||||
|         } | ||||
| 
 | ||||
|         (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true) | ||||
|  |  | |||
|  | @ -1,19 +1,34 @@ | |||
| package com.lagradost.cloudstream3.ui.download | ||||
| 
 | ||||
| import android.animation.ObjectAnimator | ||||
| import android.annotation.SuppressLint | ||||
| import android.os.Handler | ||||
| import android.os.Looper | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.animation.DecelerateInterpolator | ||||
| import android.widget.ImageView | ||||
| import android.widget.ProgressBar | ||||
| import android.widget.TextView | ||||
| import androidx.cardview.widget.CardView | ||||
| import androidx.core.widget.ContentLoadingProgressBar | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread | ||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual | ||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos | ||||
| import com.lagradost.cloudstream3.utils.VideoDownloadHelper | ||||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager | ||||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadState | ||||
| import kotlinx.android.synthetic.main.download_child_episode.view.* | ||||
| 
 | ||||
| const val DOWNLOAD_ACTION_PLAY_FILE = 0 | ||||
| const val DOWNLOAD_ACTION_DELETE_FILE = 1 | ||||
| const val DOWNLOAD_ACTION_RESUME_DOWNLOAD = 2 | ||||
| const val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3 | ||||
| 
 | ||||
| data class VisualDownloadChildCached( | ||||
|     val currentBytes: Long, | ||||
|     val totalBytes: Long, | ||||
|  | @ -56,6 +71,8 @@ class DownloadChildAdapter( | |||
|         private val extraInfo: TextView = itemView.download_child_episode_text_extra | ||||
|         private val holder: CardView = itemView.download_child_episode_holder | ||||
|         private val progressBar: ContentLoadingProgressBar = itemView.download_child_episode_progress | ||||
|         private val progressBarDownload: ContentLoadingProgressBar = itemView.download_child_episode_progress_downloaded | ||||
|         private val downloadImage: ImageView = itemView.download_child_episode_download | ||||
| 
 | ||||
|         @SuppressLint("SetTextI18n") | ||||
|         fun bind(card: VisualDownloadChildCached) { | ||||
|  | @ -73,13 +90,91 @@ class DownloadChildAdapter( | |||
| 
 | ||||
|             title.text = d.name ?: "Episode ${d.episode}" //TODO FIX | ||||
|             val totalMbString = "%.1f".format(card.totalBytes / 1000000f) | ||||
|             val currentMbString = "%.1f".format(card.currentBytes / 1000000f) | ||||
| 
 | ||||
|             extraInfo.text = | ||||
|                 "${currentMbString}MB / ${totalMbString}MB" | ||||
|             var lastState: VideoDownloadManager.DownloadType? = null | ||||
|             var currentBytes: Long = card.currentBytes | ||||
| 
 | ||||
|             fun changeDownloadImage(state: VideoDownloadManager.DownloadType) { | ||||
|                 runOnMainThread { | ||||
|                     val img = when (state) { | ||||
|                         VideoDownloadManager.DownloadType.IsPaused -> R.drawable.ic_baseline_play_arrow_24 | ||||
|                         VideoDownloadManager.DownloadType.IsDownloading -> R.drawable.netflix_pause | ||||
|                         else -> R.drawable.ic_baseline_delete_outline_24 | ||||
|                     } | ||||
|                     downloadImage?.setImageResource(img) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             fun fixDownloadedBytes(setCurrentBytes: Long, animate : Boolean) { | ||||
|                 currentBytes = setCurrentBytes | ||||
|                 runOnMainThread { | ||||
|                     val currentMbString = "%.1f".format(currentBytes / 1000000f) | ||||
| 
 | ||||
|                     extraInfo?.text = | ||||
|                         "${currentMbString}MB / ${totalMbString}MB" | ||||
| 
 | ||||
|                     progressBarDownload?.let { bar -> | ||||
|                         bar.max = (card.totalBytes / 1000).toInt() | ||||
| 
 | ||||
|                         if(animate) { | ||||
|                             val animation: ObjectAnimator = ObjectAnimator.ofInt( | ||||
|                                 bar, | ||||
|                                 "progress", | ||||
|                                 bar.progress, | ||||
|                                 (currentBytes / 1000).toInt() | ||||
|                             ) | ||||
|                             animation.duration = 500 | ||||
|                             animation.setAutoCancel(true) | ||||
|                             animation.interpolator = DecelerateInterpolator() | ||||
|                             animation.start() | ||||
|                         } else { | ||||
|                             bar.progress = (currentBytes / 1000).toInt() | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             fixDownloadedBytes(card.currentBytes, false) | ||||
|             changeDownloadImage(getDownloadState(card.data.id)) | ||||
| 
 | ||||
|             VideoDownloadManager.downloadProgressEvent += { downloadData -> | ||||
|                 if (card.data.id == downloadData.first) { | ||||
|                     fixDownloadedBytes(downloadData.second, true) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             VideoDownloadManager.downloadStatusEvent += { downloadData -> | ||||
|                 if (card.data.id == downloadData.first) { | ||||
|                     if (lastState != downloadData.second) { // TO PREVENT WASTING UI TIME | ||||
|                         lastState = downloadData.second | ||||
|                         changeDownloadImage(downloadData.second) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             holder.setOnClickListener { | ||||
|                 clickCallback.invoke(DownloadClickEvent(0, d)) | ||||
|                 clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d)) | ||||
|             } | ||||
| 
 | ||||
|             progressBarDownload.setOnClickListener { | ||||
|                 val list = arrayListOf( | ||||
|                     Pair(DOWNLOAD_ACTION_DELETE_FILE, R.string.popup_delete_file), | ||||
|                 ) | ||||
| 
 | ||||
|                 // DON'T RESUME A DOWNLOADED FILE | ||||
|                 if (lastState != VideoDownloadManager.DownloadType.IsDone && (currentBytes * 100 / card.totalBytes < 98)) { | ||||
|                     list.add( | ||||
|                         if (lastState == VideoDownloadManager.DownloadType.IsDownloading) | ||||
|                             Pair(DOWNLOAD_ACTION_PAUSE_DOWNLOAD, R.string.popup_pause_download) | ||||
|                         else | ||||
|                             Pair(DOWNLOAD_ACTION_RESUME_DOWNLOAD, R.string.popup_resume_download) | ||||
|                     ) | ||||
|                 } | ||||
| 
 | ||||
|                 it.popupMenuNoIcons( | ||||
|                     list | ||||
|                 ) { | ||||
|                     clickCallback.invoke(DownloadClickEvent(itemId, d)) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -10,10 +10,8 @@ import androidx.recyclerview.widget.GridLayoutManager | |||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar | ||||
| import com.lagradost.cloudstream3.ui.player.PlayerData | ||||
| import com.lagradost.cloudstream3.ui.player.PlayerFragment | ||||
| import com.lagradost.cloudstream3.ui.player.UriData | ||||
| import com.lagradost.cloudstream3.ui.result.getRealPosition | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.main | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKeys | ||||
|  | @ -84,32 +82,59 @@ class DownloadChildFragment : Fragment() { | |||
|             DownloadChildAdapter( | ||||
|                 ArrayList(), | ||||
|             ) { click -> | ||||
|                 if (click.action == 0) { // TODO PLAY | ||||
|                     val info = | ||||
|                         VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), click.data.id) | ||||
|                             ?: return@DownloadChildAdapter | ||||
|                 val id = click.data.id | ||||
|                 when (click.action) { | ||||
|                     DOWNLOAD_ACTION_DELETE_FILE -> { | ||||
|                         context?.let { ctx -> | ||||
|                             VideoDownloadManager.deleteFileAndUpdateSettings(ctx, id) | ||||
|                         } | ||||
|                         updateList(folder) | ||||
|                     } | ||||
|                     DOWNLOAD_ACTION_PAUSE_DOWNLOAD -> { | ||||
|                         VideoDownloadManager.downloadEvent.invoke( | ||||
|                             Pair(click.data.id, VideoDownloadManager.DownloadActionType.Pause) | ||||
|                         ) | ||||
|                         updateList(folder) | ||||
|                     } | ||||
|                     DOWNLOAD_ACTION_RESUME_DOWNLOAD -> { | ||||
|                         context?.let { ctx -> | ||||
|                             val pkg = VideoDownloadManager.getDownloadResumePackage(ctx, id) | ||||
|                             if(pkg != null) { | ||||
|                                 VideoDownloadManager.downloadFromResume(ctx, pkg) | ||||
|                             } else { | ||||
|                                 VideoDownloadManager.downloadEvent.invoke( | ||||
|                                     Pair(click.data.id, VideoDownloadManager.DownloadActionType.Resume) | ||||
|                                 ) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     DOWNLOAD_ACTION_PLAY_FILE -> { | ||||
|                         val info = | ||||
|                             VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), click.data.id) | ||||
|                                 ?: return@DownloadChildAdapter | ||||
| 
 | ||||
|                     (requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction() | ||||
|                         .setCustomAnimations( | ||||
|                             R.anim.enter_anim, | ||||
|                             R.anim.exit_anim, | ||||
|                             R.anim.pop_enter, | ||||
|                             R.anim.pop_exit | ||||
|                         ) | ||||
|                         .add( | ||||
|                             R.id.homeRoot, | ||||
|                             PlayerFragment.newInstance( | ||||
|                                 UriData( | ||||
|                                     info.path.toString(), | ||||
|                                     click.data.id, | ||||
|                                     name ?: "null", | ||||
|                                     click.data.episode, | ||||
|                                     click.data.season | ||||
|                                 ), | ||||
|                                 context?.getViewPos(click.data.id)?.position ?: 0 | ||||
|                         (requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction() | ||||
|                             .setCustomAnimations( | ||||
|                                 R.anim.enter_anim, | ||||
|                                 R.anim.exit_anim, | ||||
|                                 R.anim.pop_enter, | ||||
|                                 R.anim.pop_exit | ||||
|                             ) | ||||
|                         ) | ||||
|                         .commit() | ||||
|                             .add( | ||||
|                                 R.id.homeRoot, | ||||
|                                 PlayerFragment.newInstance( | ||||
|                                     UriData( | ||||
|                                         info.path.toString(), | ||||
|                                         click.data.id, | ||||
|                                         name ?: "null", | ||||
|                                         click.data.episode, | ||||
|                                         click.data.season | ||||
|                                     ), | ||||
|                                     context?.getViewPos(click.data.id)?.position ?: 0 | ||||
|                                 ) | ||||
|                             ) | ||||
|                             .commit() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         download_child_list.adapter = adapter | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| package com.lagradost.cloudstream3.utils | ||||
| 
 | ||||
| import android.os.Handler | ||||
| import android.os.Looper | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.Job | ||||
|  | @ -11,4 +13,10 @@ object Coroutines { | |||
|             work() | ||||
|         } | ||||
|     } | ||||
|     fun runOnMainThread(work: (() -> Unit)) { | ||||
|         val mainHandler = Handler(Looper.getMainLooper()) | ||||
|         mainHandler.post { | ||||
|             work() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -166,6 +166,16 @@ object VideoDownloadManager { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** Will return IsDone if not found or error */ | ||||
|     fun getDownloadState(id : Int) : DownloadType { | ||||
|         return try { | ||||
|             downloadStatus[id] ?: DownloadType.IsDone | ||||
|         } catch (e : Exception) { | ||||
|             e.printStackTrace() | ||||
|             DownloadType.IsDone | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private val cachedBitmaps = hashMapOf<String, Bitmap>() | ||||
|     private fun Context.getImageBitmapFromUrl(url: String): Bitmap? { | ||||
|         if (cachedBitmaps.containsKey(url)) { | ||||
|  | @ -532,6 +542,7 @@ object VideoDownloadManager { | |||
|             try { | ||||
|                 downloadStatus[ep.id] = type | ||||
|                 downloadStatusEvent.invoke(Pair(ep.id, type)) | ||||
|                 downloadProgressEvent.invoke(Pair(ep.id, bytesDownloaded)) | ||||
|             } catch (e: Exception) { | ||||
|                 // IDK MIGHT ERROR | ||||
|             } | ||||
|  | @ -584,7 +595,7 @@ object VideoDownloadManager { | |||
|                 count = connectionInputStream.read(buffer) | ||||
|                 if (count < 0) break | ||||
|                 bytesDownloaded += count | ||||
|                 downloadProgressEvent.invoke(Pair(id, bytesDownloaded)) | ||||
|                 // downloadProgressEvent.invoke(Pair(id, bytesDownloaded)) // Updates too much for any UI to keep up with | ||||
|                 while (isPaused) { | ||||
|                     sleep(100) | ||||
|                     if (isStopped) { | ||||
|  | @ -621,6 +632,7 @@ object VideoDownloadManager { | |||
|                 deleteFile() | ||||
|             } | ||||
|             else -> { | ||||
|                 downloadProgressEvent.invoke(Pair(id, bytesDownloaded)) | ||||
|                 isDone = true | ||||
|                 updateNotification() | ||||
|                 SUCCESS_DOWNLOAD_DONE | ||||
|  | @ -741,6 +753,10 @@ object VideoDownloadManager { | |||
|             downloadQueue.addLast(pkg) | ||||
|             downloadCheck(context) | ||||
|             if (setKey) saveQueue(context) | ||||
|         } else { | ||||
|             downloadEvent.invoke( | ||||
|                 Pair(pkg.item.ep.id, DownloadActionType.Resume) | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										11
									
								
								app/src/main/res/drawable/circle_shape.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/src/main/res/drawable/circle_shape.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:shape="ring" | ||||
|         android:innerRadiusRatio="2.5" | ||||
|         android:thickness="2dp" | ||||
|         android:useLevel="false"> | ||||
| 
 | ||||
|     <solid android:color="#CCC" /> | ||||
| 
 | ||||
| </shape> | ||||
							
								
								
									
										18
									
								
								app/src/main/res/drawable/circular_progress_bar.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/src/main/res/drawable/circular_progress_bar.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <rotate xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:fromDegrees="270" | ||||
|         android:toDegrees="270"> | ||||
|     <shape | ||||
|             android:innerRadiusRatio="2.5" | ||||
|             android:shape="ring" | ||||
|             android:thickness="2dp" | ||||
|             android:useLevel="true"><!-- this line fixes the issue for lollipop api 21 --> | ||||
| 
 | ||||
|         <gradient | ||||
|                 android:angle="0" | ||||
|                 android:endColor="?attr/colorPrimary" | ||||
|                 android:startColor="?attr/colorPrimary" | ||||
|                 android:type="sweep" | ||||
|                 android:useLevel="false" /> | ||||
|     </shape> | ||||
| </rotate> | ||||
|  | @ -0,0 +1,5 @@ | |||
| <vector android:height="24dp" android:tint="#FFFFFF" | ||||
|     android:viewportHeight="24" android:viewportWidth="24" | ||||
|     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <path android:fillColor="?white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,9h8v10L8,19L8,9zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/> | ||||
| </vector> | ||||
|  | @ -25,6 +25,7 @@ | |||
|     </androidx.core.widget.ContentLoadingProgressBar> | ||||
|     <GridLayout android:layout_width="match_parent" android:layout_height="match_parent"> | ||||
|         <ImageView | ||||
|                 android:visibility="gone" | ||||
|                 android:layout_marginStart="10dp" | ||||
|                 android:layout_marginEnd="10dp" | ||||
|                 android:layout_gravity="center_vertical" | ||||
|  | @ -56,18 +57,39 @@ | |||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="match_parent"> | ||||
|             </TextView> | ||||
|         </LinearLayout> | ||||
| 
 | ||||
|         <ImageView | ||||
|                 android:visibility="gone" | ||||
|                 android:layout_marginEnd="10dp" | ||||
|                 android:layout_marginStart="10dp" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:layout_width="30dp" | ||||
|                 android:id="@+id/download_child_episode_download" | ||||
|                 android:background="?selectableItemBackgroundBorderless" | ||||
|                 android:layout_gravity="center_vertical|end" | ||||
|                 android:src="@drawable/netflix_download" | ||||
|                 android:contentDescription="@string/download_descript"/> | ||||
|         </LinearLayout> | ||||
|         <FrameLayout | ||||
|                 android:layout_gravity="end" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="match_parent"> | ||||
|             <androidx.core.widget.ContentLoadingProgressBar | ||||
|                     android:layout_marginEnd="10dp" | ||||
|                     android:layout_marginStart="10dp" | ||||
|                     android:layout_width="40dp" | ||||
|                     android:layout_height="40dp" | ||||
|                     android:id="@+id/download_child_episode_progress_downloaded" | ||||
|                     android:indeterminate="false" | ||||
|                     android:progressDrawable="@drawable/circular_progress_bar" | ||||
|                     android:background="@drawable/circle_shape" | ||||
|                     style="?android:attr/progressBarStyleHorizontal" | ||||
|                     android:max="100" | ||||
|                     android:layout_margin="5dp" | ||||
|                     android:layout_gravity="end|center_vertical" | ||||
|                     android:progress="0" | ||||
|                     android:visibility="visible" | ||||
|             /> | ||||
|             <ImageView | ||||
|                     android:visibility="visible" | ||||
|                     android:layout_marginEnd="10dp" | ||||
|                     android:layout_marginStart="10dp" | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:padding="2dp" | ||||
|                     android:layout_width="30dp" | ||||
|                     android:id="@+id/download_child_episode_download" | ||||
|                     android:background="?selectableItemBackgroundBorderless" | ||||
|                     android:src="@drawable/ic_baseline_play_arrow_24" | ||||
|                     android:contentDescription="@string/download_descript"/> | ||||
|         </FrameLayout> | ||||
|     </GridLayout> | ||||
| </androidx.cardview.widget.CardView> | ||||
|  | @ -101,7 +101,7 @@ | |||
| 
 | ||||
|             </ImageView>--> | ||||
|             <TextView | ||||
|                     android:text="Dub" | ||||
|                     android:text="@string/app_dubbed_text" | ||||
|                     android:id="@+id/text_is_dub" | ||||
|                     android:textColor="@color/textColor" | ||||
|                     android:paddingRight="10dp" | ||||
|  | @ -117,7 +117,7 @@ | |||
|             </TextView> | ||||
|             <TextView | ||||
|                     android:id="@+id/text_is_sub" | ||||
|                     android:text="Sub" | ||||
|                     android:text="@string/app_subbed_text" | ||||
|                     android:layout_gravity="end" | ||||
|                     android:textColor="@color/textColor" | ||||
|                     android:paddingRight="10dp" | ||||
|  |  | |||
|  | @ -42,4 +42,9 @@ | |||
|     <string name="error_loading_links">Error Loading Links</string> | ||||
|     <string name="download_storage_text">Internal Storage</string> | ||||
|     <string name="options">Options</string> | ||||
|     <string name="app_dubbed_text">Dub</string> | ||||
|     <string name="app_subbed_text">Sub</string> | ||||
|     <string name="popup_delete_file">Delete File</string> | ||||
|     <string name="popup_resume_download">Resume Download</string> | ||||
|     <string name="popup_pause_download">Pause Download</string> | ||||
| </resources> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue