mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	downloads playable
This commit is contained in:
		
							parent
							
								
									3bf76a9563
								
							
						
					
					
						commit
						5ffb53bf1c
					
				
					 11 changed files with 405 additions and 175 deletions
				
			
		|  | @ -1,25 +1,29 @@ | |||
| package com.lagradost.cloudstream3 | ||||
| 
 | ||||
| import android.R.attr | ||||
| import android.app.PictureInPictureParams | ||||
| import android.content.ComponentName | ||||
| import android.content.Intent | ||||
| import android.content.pm.PackageManager | ||||
| import android.content.res.ColorStateList | ||||
| import android.os.Build | ||||
| import android.os.Bundle | ||||
| import android.widget.Toast | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.navigation.NavOptions | ||||
| import androidx.navigation.findNavController | ||||
| import androidx.navigation.fragment.NavHostFragment | ||||
| import androidx.navigation.ui.AppBarConfiguration | ||||
| import androidx.navigation.ui.setupWithNavController | ||||
| import com.google.android.gms.cast.framework.CastButtonFactory | ||||
| import com.google.android.material.bottomnavigation.BottomNavigationView | ||||
| import com.lagradost.cloudstream3.UIHelper.checkWrite | ||||
| import com.lagradost.cloudstream3.UIHelper.getResourceColor | ||||
| import com.lagradost.cloudstream3.UIHelper.hasPIPPermission | ||||
| import com.lagradost.cloudstream3.UIHelper.isUsingMobileData | ||||
| import com.lagradost.cloudstream3.UIHelper.requestRW | ||||
| import com.lagradost.cloudstream3.UIHelper.shouldShowPIPMode | ||||
| import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver | ||||
| import com.lagradost.cloudstream3.ui.download.DownloadChildFragment | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKeys | ||||
| import com.lagradost.cloudstream3.utils.DataStore.removeKey | ||||
|  | @ -54,6 +58,7 @@ class MainActivity : AppCompatActivity() { | |||
|         var canShowPipMode: Boolean = false | ||||
|         var isInPIPMode: Boolean = false | ||||
|         lateinit var mainContext: MainActivity | ||||
|         lateinit var navOptions: NavOptions | ||||
| 
 | ||||
|         //https://github.com/anggrayudi/SimpleStorage/blob/4eb6306efb6cdfae4e34f170c8b9d4e135b04d51/sample/src/main/java/com/anggrayudi/storage/sample/activity/MainActivity.kt#L624 | ||||
|         const val REQUEST_CODE_STORAGE_ACCESS = 1 | ||||
|  | @ -89,6 +94,17 @@ class MainActivity : AppCompatActivity() { | |||
|             it.isVisible | ||||
|         } | ||||
| 
 | ||||
|         if (currentFragment is NavHostFragment) { | ||||
|             val child = currentFragment.childFragmentManager.fragments.last { | ||||
|                 it.isVisible | ||||
|             } | ||||
|             if (child is DownloadChildFragment) { | ||||
|                 val navController = findNavController(R.id.nav_host_fragment) | ||||
|                 navController.navigate(R.id.navigation_downloads, Bundle(), navOptions) | ||||
|                 return true | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (currentFragment != null && supportFragmentManager.fragments.size > 2) { | ||||
|             //MainActivity.showNavbar() | ||||
|             supportFragmentManager.beginTransaction() | ||||
|  | @ -146,15 +162,35 @@ class MainActivity : AppCompatActivity() { | |||
|                     hasPIPPermission() // CHECK IF FEATURE IS ENABLED IN SETTINGS | ||||
| 
 | ||||
|         val navController = findNavController(R.id.nav_host_fragment) | ||||
|         // Passing each menu ID as a set of Ids because each | ||||
|         // menu should be considered as top level destinations. | ||||
|         val appBarConfiguration = AppBarConfiguration( | ||||
|             setOf( | ||||
|                 R.id.navigation_home, R.id.navigation_search, R.id.navigation_notifications | ||||
|             ) | ||||
|         ) | ||||
|         //setupActionBarWithNavController(navController, appBarConfiguration) | ||||
|         navView.setupWithNavController(navController) | ||||
| 
 | ||||
|         navOptions = NavOptions.Builder() | ||||
|             .setLaunchSingleTop(true) | ||||
|             .setEnterAnim(R.anim.nav_enter_anim) | ||||
|             .setExitAnim(R.anim.nav_exit_anim) | ||||
|             .setPopEnterAnim(R.anim.nav_pop_enter) | ||||
|             .setPopExitAnim(R.anim.nav_pop_exit) | ||||
|             .setPopUpTo(navController.graph.startDestination, false) | ||||
|             .build() | ||||
| 
 | ||||
|         navView.setOnNavigationItemSelectedListener { item -> | ||||
|             when (item.itemId) { | ||||
|                // R.id.navigation_home -> { | ||||
|                    // navController.navigate(R.id.navigation_home, null, navOptions) | ||||
|                 //} | ||||
|                 R.id.navigation_search -> { | ||||
|                     navController.navigate(R.id.navigation_search, null, navOptions) | ||||
|                 } | ||||
|                 R.id.navigation_downloads -> { | ||||
|                     navController.navigate(R.id.navigation_downloads, null, navOptions) | ||||
|                 } | ||||
|                 R.id.navigation_settings -> { | ||||
|                     navController.navigate(R.id.navigation_settings, null, navOptions) | ||||
|                 } | ||||
|             } | ||||
|             true | ||||
|         } | ||||
| 
 | ||||
|         navView.itemRippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f)) | ||||
| 
 | ||||
|         if (!checkWrite()) { | ||||
|             requestRW() | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ import android.view.MenuItem | |||
| import android.view.View | ||||
| import android.view.WindowManager | ||||
| import android.view.inputmethod.InputMethodManager | ||||
| import androidx.annotation.AttrRes | ||||
| import androidx.annotation.ColorInt | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.appcompat.view.ContextThemeWrapper | ||||
|  | @ -26,6 +27,10 @@ import androidx.appcompat.view.menu.MenuBuilder | |||
| import androidx.appcompat.widget.PopupMenu | ||||
| import androidx.core.app.ActivityCompat | ||||
| import androidx.core.content.ContextCompat | ||||
| import androidx.core.graphics.alpha | ||||
| import androidx.core.graphics.blue | ||||
| import androidx.core.graphics.green | ||||
| import androidx.core.graphics.red | ||||
| import androidx.fragment.app.FragmentActivity | ||||
| import androidx.preference.PreferenceManager | ||||
| import com.google.android.gms.cast.framework.CastContext | ||||
|  | @ -59,6 +64,20 @@ object UIHelper { | |||
|             1337) | ||||
|     } | ||||
| 
 | ||||
|     @ColorInt | ||||
|     fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int { | ||||
|         val typedArray = obtainStyledAttributes(intArrayOf(resource)) | ||||
|         val color = typedArray.getColor(0, 0) | ||||
|         typedArray.recycle() | ||||
| 
 | ||||
|         if (alphaFactor < 1f) { | ||||
|             val alpha = (color.alpha * alphaFactor).roundToInt() | ||||
|             return Color.argb(alpha, color.red, color.green, color.blue) | ||||
|         } | ||||
| 
 | ||||
|         return color | ||||
|     } | ||||
| 
 | ||||
|     fun AppCompatActivity.loadResult(url: String, slug: String, apiName: String) { | ||||
|         this.runOnUiThread { | ||||
|             viewModelStore.clear() | ||||
|  |  | |||
|  | @ -4,14 +4,20 @@ import android.os.Bundle | |||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.fragment.app.Fragment | ||||
| 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 | ||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos | ||||
| import com.lagradost.cloudstream3.utils.VideoDownloadHelper | ||||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager | ||||
| import kotlinx.android.synthetic.main.fragment_child_downloads.* | ||||
|  | @ -68,6 +74,11 @@ class DownloadChildFragment : Fragment() { | |||
|         } | ||||
|         context?.fixPaddingStatusbar(download_child_root) | ||||
| 
 | ||||
|         download_child_toolbar.title = name | ||||
|         download_child_toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24) | ||||
|         download_child_toolbar.setNavigationOnClickListener { | ||||
|             activity?.onBackPressed() | ||||
|         } | ||||
| 
 | ||||
|         val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = | ||||
|             DownloadChildAdapter( | ||||
|  | @ -77,6 +88,28 @@ class DownloadChildFragment : Fragment() { | |||
|                     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 | ||||
|                             ) | ||||
|                         ) | ||||
|                         .commit() | ||||
|                 } | ||||
|             } | ||||
|         download_child_list.adapter = adapter | ||||
|  |  | |||
|  | @ -8,8 +8,10 @@ import android.view.ViewGroup | |||
| import android.widget.LinearLayout | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.lifecycle.ViewModelProvider | ||||
| import androidx.navigation.findNavController | ||||
| import androidx.recyclerview.widget.GridLayoutManager | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.lagradost.cloudstream3.MainActivity | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar | ||||
| import com.lagradost.cloudstream3.isMovieType | ||||
|  | @ -64,6 +66,7 @@ class DownloadFragment : Fragment() { | |||
|         observe(downloadsViewModel.downloadBytes) { | ||||
|             download_app_txt?.text = "App • ${getBytesAsText(it)}GB" | ||||
|             download_app?.setLayoutWidth(it) | ||||
|             download_storage_appbar?.visibility = View.VISIBLE | ||||
|         } | ||||
|         return inflater.inflate(R.layout.fragment_downloads, container, false) | ||||
|     } | ||||
|  | @ -79,10 +82,11 @@ class DownloadFragment : Fragment() { | |||
|                 } | ||||
|                 else { | ||||
|                     val folder = getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString()) | ||||
|                     activity?.supportFragmentManager?.beginTransaction() | ||||
|                         ?.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit) | ||||
|                         ?.add(R.id.homeRoot, DownloadChildFragment.newInstance(click.data.name, folder)) | ||||
|                         ?.commit() | ||||
|                     val navController = activity?.findNavController(R.id.nav_host_fragment) | ||||
|                     navController?.navigate(R.id.navigation_download_child, Bundle().apply { | ||||
|                             putString("folder", folder) | ||||
|                             putString("name", click.data.name) | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|         download_list.adapter = adapter | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ import androidx.transition.TransitionManager | |||
| import com.fasterxml.jackson.databind.DeserializationFeature | ||||
| import com.fasterxml.jackson.databind.json.JsonMapper | ||||
| import com.fasterxml.jackson.module.kotlin.KotlinModule | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.google.android.exoplayer2.* | ||||
| import com.google.android.exoplayer2.C.TIME_UNSET | ||||
| import com.google.android.exoplayer2.source.DefaultMediaSourceFactory | ||||
|  | @ -71,6 +72,7 @@ import com.lagradost.cloudstream3.mvvm.observe | |||
| import com.lagradost.cloudstream3.mvvm.observeDirectly | ||||
| import com.lagradost.cloudstream3.ui.result.ResultEpisode | ||||
| import com.lagradost.cloudstream3.ui.result.ResultViewModel | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.getVideoContentUri | ||||
| import com.lagradost.cloudstream3.utils.CastHelper.startCast | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||
| import com.lagradost.cloudstream3.utils.DataStore.setKey | ||||
|  | @ -81,7 +83,6 @@ import com.lagradost.cloudstream3.utils.getId | |||
| import kotlinx.android.synthetic.main.fragment_player.* | ||||
| import kotlinx.android.synthetic.main.player_custom_layout.* | ||||
| import kotlinx.coroutines.* | ||||
| import java.io.File | ||||
| import javax.net.ssl.HttpsURLConnection | ||||
| import javax.net.ssl.SSLContext | ||||
| import javax.net.ssl.SSLSession | ||||
|  | @ -131,6 +132,14 @@ data class PlayerData( | |||
|     val mirrorId: Int, | ||||
| ) | ||||
| 
 | ||||
| data class UriData( | ||||
|     val uri: String, | ||||
|     val id: Int?, | ||||
|     val name: String, | ||||
|     val episode: Int?, | ||||
|     val season: Int?, | ||||
| ) | ||||
| 
 | ||||
| // YE, I KNOW, THIS COULD BE HANDLED A LOT BETTER | ||||
| class PlayerFragment : Fragment() { | ||||
|     private var isCurrentlyPlaying: Boolean = false | ||||
|  | @ -143,6 +152,9 @@ class PlayerFragment : Fragment() { | |||
|     private var isPlayerPlaying = true | ||||
|     private lateinit var viewModel: ResultViewModel | ||||
|     private lateinit var playerData: PlayerData | ||||
|     private lateinit var uriData: UriData | ||||
|     private var isDownloadedFile = false | ||||
|     private var downloadId = 0 | ||||
|     private var isLoading = true | ||||
|     private var isShowing = true | ||||
|     private lateinit var exoPlayer: SimpleExoPlayer | ||||
|  | @ -598,14 +610,31 @@ class PlayerFragment : Fragment() { | |||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         fun newInstance(uriData: UriData, startPos: Long? = null) = | ||||
|             PlayerFragment().apply { | ||||
|                 arguments = Bundle().apply { | ||||
|                     //println(data) | ||||
|                     putString("uriData", mapper.writeValueAsString(uriData)) | ||||
| 
 | ||||
|                     if (startPos != null) { | ||||
|                         putLong(STATE_RESUME_POSITION, startPos) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     private fun savePos() { | ||||
|         if (this::exoPlayer.isInitialized) { | ||||
|             if (exoPlayer.duration > 0 && exoPlayer.currentPosition > 0) { | ||||
|                 context?.let { ctx -> | ||||
|                     ctx.setViewPos(getEpisode()?.id, exoPlayer.currentPosition, exoPlayer.duration) | ||||
|                     viewModel.reloadEpisodes(ctx) | ||||
|                     ctx.setViewPos( | ||||
|                         if (isDownloadedFile) uriData.id else getEpisode()?.id, | ||||
|                         exoPlayer.currentPosition, | ||||
|                         exoPlayer.duration | ||||
|                     ) | ||||
|                     if (!isDownloadedFile) | ||||
|                         viewModel.reloadEpisodes(ctx) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -774,7 +803,7 @@ class PlayerFragment : Fragment() { | |||
|         navigationBarHeight = requireContext().getNavigationBarHeight() | ||||
|         statusBarHeight = requireContext().getStatusBarHeight() | ||||
| 
 | ||||
|         if (activity?.isCastApiAvailable() == true) { | ||||
|         if (activity?.isCastApiAvailable() == true && !isDownloadedFile) { | ||||
|             CastButtonFactory.setUpMediaRouteButton(activity, player_media_route_button) | ||||
|             val castContext = CastContext.getSharedInstance(requireContext()) | ||||
| 
 | ||||
|  | @ -852,14 +881,24 @@ class PlayerFragment : Fragment() { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         isDownloadedFile = false | ||||
|         arguments?.getString("uriData")?.let { | ||||
|             uriData = mapper.readValue(it) | ||||
|             isDownloadedFile = true | ||||
|         } | ||||
| 
 | ||||
|         arguments?.getString("data")?.let { | ||||
|             playerData = mapper.readValue(it, PlayerData::class.java) | ||||
|             playerData = mapper.readValue(it) | ||||
|         } | ||||
| 
 | ||||
|         arguments?.getLong(STATE_RESUME_POSITION)?.let { | ||||
|             playbackPosition = it | ||||
|         } | ||||
| 
 | ||||
|         sources_btt.visibility = | ||||
|             if (isDownloadedFile) View.GONE else View.VISIBLE | ||||
|         player_media_route_button.visibility = | ||||
|             if (isDownloadedFile) View.GONE else View.VISIBLE | ||||
|         if (savedInstanceState != null) { | ||||
|             currentWindow = savedInstanceState.getInt(STATE_RESUME_WINDOW) | ||||
|             playbackPosition = savedInstanceState.getLong(STATE_RESUME_POSITION) | ||||
|  | @ -883,60 +922,61 @@ class PlayerFragment : Fragment() { | |||
|                 android.provider.Settings.System.CONTENT_URI, true, volumeObserver | ||||
|             ) | ||||
| 
 | ||||
|         viewModel = ViewModelProvider(requireActivity()).get(ResultViewModel::class.java) | ||||
|         if (!isDownloadedFile) { | ||||
|             viewModel = ViewModelProvider(requireActivity()).get(ResultViewModel::class.java) | ||||
| 
 | ||||
|         observeDirectly(viewModel.episodes) { _episodes -> | ||||
|             episodes = _episodes | ||||
|             if (isLoading) { | ||||
|                 if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) { | ||||
|             observeDirectly(viewModel.episodes) { _episodes -> | ||||
|                 episodes = _episodes | ||||
|                 if (isLoading) { | ||||
|                     if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) { | ||||
| 
 | ||||
|                 } else { | ||||
|                     // WHAT THE FUCK DID YOU DO | ||||
|                     } else { | ||||
|                         // WHAT THE FUCK DID YOU DO | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         observe(viewModel.apiName) { | ||||
|             apiName = it | ||||
|         } | ||||
|             observe(viewModel.apiName) { | ||||
|                 apiName = it | ||||
|             } | ||||
| 
 | ||||
|         overlay_loading_skip_button?.alpha = 0.5f | ||||
|         observeDirectly(viewModel.allEpisodes) { _allEpisodes -> | ||||
|             allEpisodes = _allEpisodes | ||||
|             overlay_loading_skip_button?.alpha = 0.5f | ||||
|             observeDirectly(viewModel.allEpisodes) { _allEpisodes -> | ||||
|                 allEpisodes = _allEpisodes | ||||
| 
 | ||||
|             val current = getUrls() | ||||
|             if (current != null) { | ||||
|                 if (current.isNotEmpty()) { | ||||
|                     overlay_loading_skip_button?.alpha = 1f | ||||
|                 val current = getUrls() | ||||
|                 if (current != null) { | ||||
|                     if (current.isNotEmpty()) { | ||||
|                         overlay_loading_skip_button?.alpha = 1f | ||||
|                     } else { | ||||
|                         overlay_loading_skip_button?.alpha = 0.5f | ||||
|                     } | ||||
|                 } else { | ||||
|                     overlay_loading_skip_button?.alpha = 0.5f | ||||
|                 } | ||||
|             } else { | ||||
|                 overlay_loading_skip_button?.alpha = 0.5f | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         observeDirectly(viewModel.allEpisodesSubs) { _allEpisodesSubs -> | ||||
|             allEpisodesSubs = _allEpisodesSubs | ||||
|         } | ||||
|             observeDirectly(viewModel.allEpisodesSubs) { _allEpisodesSubs -> | ||||
|                 allEpisodesSubs = _allEpisodesSubs | ||||
|             } | ||||
| 
 | ||||
|         observeDirectly(viewModel.resultResponse) { data -> | ||||
|             when (data) { | ||||
|                 is Resource.Success -> { | ||||
|                     val d = data.value | ||||
|                     if (d is LoadResponse) { | ||||
|                         localData = d | ||||
|                         currentPoster = d.posterUrl | ||||
|                         currentHeaderName = d.name | ||||
|                         currentIsMovie = !d.isEpisodeBased() | ||||
|             observeDirectly(viewModel.resultResponse) { data -> | ||||
|                 when (data) { | ||||
|                     is Resource.Success -> { | ||||
|                         val d = data.value | ||||
|                         if (d is LoadResponse) { | ||||
|                             localData = d | ||||
|                             currentPoster = d.posterUrl | ||||
|                             currentHeaderName = d.name | ||||
|                             currentIsMovie = !d.isEpisodeBased() | ||||
|                         } | ||||
|                     } | ||||
|                     is Resource.Failure -> { | ||||
|                         //WTF, HOW DID YOU EVEN GET HERE | ||||
|                     } | ||||
|                 } | ||||
|                 is Resource.Failure -> { | ||||
|                     //WTF, HOW DID YOU EVEN GET HERE | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         val fastForwardTime = settingsManager.getInt("fast_forward_button_time", 10) | ||||
|         exo_rew_text.text = fastForwardTime.toString() | ||||
|         exo_ffwd_text.text = fastForwardTime.toString() | ||||
|  | @ -1193,7 +1233,7 @@ class PlayerFragment : Fragment() { | |||
|     } | ||||
| 
 | ||||
|     private fun hasNextEpisode(): Boolean { | ||||
|         return episodes.size > playerData.episodeIndex + 1 | ||||
|         return !isDownloadedFile && episodes.size > playerData.episodeIndex + 1 // TODO FIX DOWNLOADS NEXT EPISODE | ||||
|     } | ||||
| 
 | ||||
|     private var isCurrentlySkippingEp = false | ||||
|  | @ -1335,8 +1375,8 @@ class PlayerFragment : Fragment() { | |||
|     private val updateProgressAction = Runnable { updateProgressBar() }*/ | ||||
| 
 | ||||
|     @SuppressLint("SetTextI18n") | ||||
|     fun initPlayer(currentUrl: ExtractorLink?) { | ||||
|         if (currentUrl == null) return | ||||
|     fun initPlayer(currentUrl: ExtractorLink?, uri: String? = null) { | ||||
|         if (currentUrl == null && uri == null) return | ||||
|         isCurrentlyPlaying = true | ||||
|         hasUsedFirstRender = false | ||||
| 
 | ||||
|  | @ -1347,9 +1387,9 @@ class PlayerFragment : Fragment() { | |||
|                 exoPlayer.release() | ||||
|             } | ||||
|             val isOnline = | ||||
|                 currentUrl.url.startsWith("https://") || currentUrl.url.startsWith("http://") | ||||
|                 currentUrl != null && (currentUrl.url.startsWith("https://") || currentUrl.url.startsWith("http://")) | ||||
| 
 | ||||
|             if (settingsManager.getBoolean("ignore_ssl", true)) { | ||||
|             if (settingsManager.getBoolean("ignore_ssl", true) && !isDownloadedFile) { | ||||
|                 // Disables ssl check | ||||
|                 val sslContext: SSLContext = SSLContext.getInstance("TLS") | ||||
|                 sslContext.init(null, arrayOf(SSLTrustManager()), java.security.SecureRandom()) | ||||
|  | @ -1367,7 +1407,8 @@ class PlayerFragment : Fragment() { | |||
|                         /*FastAniApi.currentHeaders?.forEach { | ||||
|                             dataSource.setRequestProperty(it.key, it.value) | ||||
|                         }*/ | ||||
|                         dataSource.setRequestProperty("Referer", currentUrl.referer) | ||||
|                         if (currentUrl != null) | ||||
|                             dataSource.setRequestProperty("Referer", currentUrl.referer) | ||||
|                         dataSource | ||||
|                     } else { | ||||
|                         DefaultDataSourceFactory(requireContext(), USER_AGENT).createDataSource() | ||||
|  | @ -1375,15 +1416,31 @@ class PlayerFragment : Fragment() { | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             val mimeType = if (currentUrl.isM3u8) MimeTypes.APPLICATION_M3U8 else MimeTypes.APPLICATION_MP4 | ||||
|             val mimeType = | ||||
|                 if (currentUrl == null && uri != null) | ||||
|                     MimeTypes.APPLICATION_MP4 else | ||||
|                     if (currentUrl?.isM3u8 == true) | ||||
|                         MimeTypes.APPLICATION_M3U8 | ||||
|                     else | ||||
|                         MimeTypes.APPLICATION_MP4 | ||||
| 
 | ||||
|             val mediaItemBuilder = MediaItem.Builder() | ||||
|                 //Replace needed for android 6.0.0  https://github.com/google/ExoPlayer/issues/5983 | ||||
|                 .setMimeType(mimeType) | ||||
| 
 | ||||
|             if (isOnline) { | ||||
|             if (currentUrl != null) { | ||||
|                 mediaItemBuilder.setUri(currentUrl.url) | ||||
|             } else { | ||||
|                 mediaItemBuilder.setUri(Uri.fromFile(File(currentUrl.url))) | ||||
|             } else if (uri != null) { | ||||
|                 val uriPrimary = Uri.parse(uri) | ||||
|                 if (uriPrimary.scheme == "content") { | ||||
|                     mediaItemBuilder.setUri(uriPrimary) | ||||
|                     //      video_title?.text = uriPrimary.toString() | ||||
|                 } else { | ||||
|                     //mediaItemBuilder.setUri(Uri.parse(currentUrl.url)) | ||||
|                     val realUri = getVideoContentUri(requireContext(), uri) | ||||
|                     //    video_title?.text = uri.toString() | ||||
|                     mediaItemBuilder.setUri(realUri) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             val mediaItem = mediaItemBuilder.build() | ||||
|  | @ -1401,7 +1458,7 @@ class PlayerFragment : Fragment() { | |||
|                     .setTrackSelector(trackSelector) | ||||
| 
 | ||||
|             _exoPlayer.setMediaSourceFactory(DefaultMediaSourceFactory(CustomFactory())) | ||||
|             println("START POS: " + playbackPosition) | ||||
| 
 | ||||
|             exoPlayer = _exoPlayer.build().apply { | ||||
|                 playWhenReady = isPlayerPlaying | ||||
|                 seekTo(currentWindow, playbackPosition) | ||||
|  | @ -1431,24 +1488,38 @@ class PlayerFragment : Fragment() { | |||
|             exoPlayer.playbackParameters = PlaybackParameters(playbackSpeed) | ||||
|             player_speed_text?.text = "Speed (${playbackSpeed}x)".replace(".0x", "x") | ||||
| 
 | ||||
|             if (localData != null) { | ||||
|             var hName: String? = null | ||||
|             var epEpisode: Int? = null | ||||
|             var epSeason: Int? = null | ||||
|             var isEpisodeBased = true | ||||
| 
 | ||||
|             if (isDownloadedFile) { | ||||
|                 hName = uriData.name | ||||
|                 epEpisode = uriData.episode | ||||
|                 epSeason = uriData.season | ||||
|                 isEpisodeBased = epEpisode != null | ||||
|                 video_title_rez?.text = "" | ||||
|             } else if (localData != null && currentUrl != null) { | ||||
|                 val data = localData!! | ||||
|                 val localEpisode = getEpisode() | ||||
|                 if (localEpisode != null) { | ||||
|                     val episode = localEpisode.episode | ||||
|                     val season: Int? = localEpisode.season | ||||
|                     val isEpisodeBased = data.isEpisodeBased() | ||||
|                     video_title?.text = data.name + | ||||
|                             if (isEpisodeBased) | ||||
|                                 if (season == null) | ||||
|                                     " - Episode $episode" | ||||
|                                 else | ||||
|                                     " \"S${season}:E${episode}\"" | ||||
|                             else "" | ||||
|                     epEpisode = localEpisode.episode | ||||
|                     epSeason = localEpisode.season | ||||
|                     hName = data.name | ||||
|                     isEpisodeBased = data.isEpisodeBased() | ||||
|                     video_title_rez?.text = currentUrl.name | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             //TODO FIX | ||||
|             video_title?.text = hName + | ||||
|                     if (isEpisodeBased) | ||||
|                         if (epSeason == null) | ||||
|                             " - Episode $epEpisode" | ||||
|                         else | ||||
|                             " \"S${epSeason}:E${epEpisode}\"" | ||||
|                     else "" | ||||
| 
 | ||||
| /* | ||||
|             exo_remaining.text = Util.getStringForTime(formatBuilder, | ||||
|                 formatter, | ||||
|  | @ -1465,8 +1536,10 @@ class PlayerFragment : Fragment() { | |||
| 
 | ||||
|                     val height = exoPlayer.videoFormat?.height | ||||
|                     val width = exoPlayer.videoFormat?.width | ||||
| 
 | ||||
|                     video_title_rez?.text = | ||||
|                         if (height == null || width == null) currentUrl.name else "${currentUrl.name} - ${width}x${height}" | ||||
|                         if (height == null || width == null) currentUrl?.name | ||||
|                             ?: "" else if (isDownloadedFile) "${width}x${height}" else "${currentUrl?.name} - ${width}x${height}" | ||||
| 
 | ||||
|                     if (!hasUsedFirstRender) { // DON'T WANT TO SET MULTIPLE MESSAGES | ||||
|                         changeSkip() | ||||
|  | @ -1521,11 +1594,11 @@ class PlayerFragment : Fragment() { | |||
|                 } | ||||
| 
 | ||||
|                 override fun onPlayerError(error: ExoPlaybackException) { | ||||
|                     println("CURRENT URL: " + currentUrl.url) | ||||
|                     println("CURRENT URL: " + currentUrl?.url ?: uri) | ||||
|                     // Lets pray this doesn't spam Toasts :) | ||||
|                     when (error.type) { | ||||
|                         ExoPlaybackException.TYPE_SOURCE -> { | ||||
|                             if (currentUrl.url != "") { | ||||
|                             if (currentUrl?.url != "") { | ||||
|                                 Toast.makeText( | ||||
|                                     activity, | ||||
|                                     "Source error\n" + error.sourceException.message, | ||||
|  | @ -1565,6 +1638,9 @@ class PlayerFragment : Fragment() { | |||
|     //http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4 | ||||
|     @SuppressLint("SetTextI18n") | ||||
|     private fun initPlayer() { | ||||
|         if (isDownloadedFile) { | ||||
|             initPlayer(null, uriData.uri) | ||||
|         } | ||||
|         println("INIT PLAYER") | ||||
|         view?.setOnTouchListener { _, _ -> return@setOnTouchListener true } // VERY IMPORTANT https://stackoverflow.com/questions/28818926/prevent-clicking-on-a-button-in-an-activity-while-showing-a-fragment | ||||
|         val tempCurrentUrls = getUrls() | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| package com.lagradost.cloudstream3.utils | ||||
| 
 | ||||
| import android.content.ContentValues | ||||
| import android.content.Context | ||||
| import android.net.Uri | ||||
| import android.provider.MediaStore | ||||
| 
 | ||||
| object AppUtils { | ||||
|     fun getVideoContentUri(context: Context, videoFilePath: String): Uri? { | ||||
|         val cursor = context.contentResolver.query( | ||||
|             MediaStore.Video.Media.EXTERNAL_CONTENT_URI, arrayOf(MediaStore.Video.Media._ID), | ||||
|             MediaStore.Video.Media.DATA + "=? ", arrayOf(videoFilePath), null | ||||
|         ) | ||||
|         return if (cursor != null && cursor.moveToFirst()) { | ||||
|             val id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)) | ||||
|             cursor.close() | ||||
|             Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "" + id) | ||||
|         } else { | ||||
|             val values = ContentValues() | ||||
|             values.put(MediaStore.Video.Media.DATA, videoFilePath) | ||||
|             context.contentResolver.insert( | ||||
|                 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,6 +1,6 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
|         android:background="@color/bitDarkerGrayBackground" | ||||
| <androidx.coordinatorlayout.widget.CoordinatorLayout | ||||
|         android:background="?attr/darkBackground" | ||||
|         android:id="@+id/download_child_root" | ||||
|         android:orientation="vertical" | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|  | @ -9,11 +9,29 @@ | |||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         tools:context=".ui.download.DownloadFragment"> | ||||
|     <com.google.android.material.appbar.AppBarLayout | ||||
|             android:background="@android:color/transparent" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content"> | ||||
|         <com.google.android.material.appbar.MaterialToolbar | ||||
|                 android:id="@+id/download_child_toolbar" | ||||
|                 android:paddingTop="@dimen/navbarHeight" | ||||
|                 tools:title="Overlord" | ||||
|                 android:background="?attr/darkBackground" | ||||
|                 app:navigationIconTint="?attr/iconColor" | ||||
|                 app:titleTextColor="?attr/textColor" | ||||
|                 app:layout_scrollFlags="scroll|enterAlways" | ||||
|                 android:layout_width="match_parent" android:layout_height="wrap_content"> | ||||
|         </com.google.android.material.appbar.MaterialToolbar> | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|             android:layout_margin="10dp" | ||||
|             android:background="?attr/bitDarkerGrayBackground" | ||||
|             app:layout_behavior="@string/appbar_scrolling_view_behavior" | ||||
|             android:padding="10dp" | ||||
|             tools:listitem="@layout/download_child_episode" | ||||
|             android:id="@+id/download_child_list" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content"> | ||||
|             android:layout_height="match_parent"> | ||||
|     </androidx.recyclerview.widget.RecyclerView> | ||||
| </LinearLayout> | ||||
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | ||||
|  | @ -1,5 +1,5 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| <androidx.coordinatorlayout.widget.CoordinatorLayout | ||||
|         android:id="@+id/download_root" | ||||
|         android:orientation="vertical" | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|  | @ -7,100 +7,114 @@ | |||
|         xmlns:tools="http://schemas.android.com/tools" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:background="?attr/darkBackground" | ||||
|         tools:context=".ui.download.DownloadFragment"> | ||||
|     <LinearLayout | ||||
|             android:layout_margin="10dp" | ||||
|             android:orientation="vertical" | ||||
|     <com.google.android.material.appbar.AppBarLayout | ||||
|             android:background="?attr/darkBackground" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content"> | ||||
|         <TextView | ||||
|                 android:layout_marginBottom="5dp" | ||||
|                 android:text="@string/download_storage_text" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content"> | ||||
|         </TextView> | ||||
|         <!-- | ||||
|         For Scroll add to LinearLayout | ||||
|         app:layout_scrollFlags="scroll|enterAlways" | ||||
|         --> | ||||
|         <LinearLayout | ||||
|                 android:layout_marginBottom="5dp" | ||||
|                 android:layout_width="fill_parent" | ||||
|                 android:layout_height="12dp" | ||||
|                 android:orientation="horizontal"> | ||||
|             <View | ||||
|                     android:layout_weight="0.5" | ||||
|                     android:id="@+id/download_used" | ||||
|                     android:background="@color/usedStorageColor" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="match_parent"/> | ||||
|             <View | ||||
|                     android:id="@+id/download_app" | ||||
|                     android:layout_weight="0.10" | ||||
|                     android:background="?attr/colorPrimary" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="match_parent"/> | ||||
|             <View | ||||
|                     android:id="@+id/download_free" | ||||
|                     android:layout_weight="0.10" | ||||
|                     android:background="@color/freeStorageColor" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="match_parent"/> | ||||
|         </LinearLayout> | ||||
|         <LinearLayout | ||||
|                 android:orientation="horizontal" | ||||
|                 android:id="@+id/download_storage_appbar" | ||||
|                 android:visibility="gone" | ||||
|                 android:layout_margin="10dp" | ||||
|                 android:orientation="vertical" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content"> | ||||
|             <View | ||||
|                     android:layout_marginEnd="5dp" | ||||
|                     android:layout_marginTop="5dp" | ||||
|             <TextView | ||||
|                     android:layout_marginBottom="5dp" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:background="@color/usedStorageColor" | ||||
|                     android:layout_width="10dp" | ||||
|                     android:layout_height="10dp"/> | ||||
|             <TextView | ||||
|                     android:id="@+id/download_used_txt" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     tools:text="Used • 30.58GB" | ||||
|                     android:textSize="12sp" | ||||
|                     android:textColor="?attr/textColor" | ||||
|                     android:text="@string/download_storage_text" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content"/> | ||||
|                     android:layout_height="wrap_content"> | ||||
|             </TextView> | ||||
|             <LinearLayout | ||||
|                     android:layout_marginBottom="5dp" | ||||
|                     android:layout_width="fill_parent" | ||||
|                     android:layout_height="12dp" | ||||
|                     android:orientation="horizontal"> | ||||
|                 <View | ||||
|                         android:layout_weight="0.5" | ||||
|                         android:id="@+id/download_used" | ||||
|                         android:background="@color/usedStorageColor" | ||||
|                         android:layout_width="0dp" | ||||
|                         android:layout_height="match_parent"/> | ||||
|                 <View | ||||
|                         android:id="@+id/download_app" | ||||
|                         android:layout_weight="0.10" | ||||
|                         android:background="?attr/colorPrimary" | ||||
|                         android:layout_width="0dp" | ||||
|                         android:layout_height="match_parent"/> | ||||
|                 <View | ||||
|                         android:id="@+id/download_free" | ||||
|                         android:layout_weight="0.10" | ||||
|                         android:background="@color/freeStorageColor" | ||||
|                         android:layout_width="0dp" | ||||
|                         android:layout_height="match_parent"/> | ||||
|             </LinearLayout> | ||||
|             <LinearLayout | ||||
|                     android:orientation="horizontal" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content"> | ||||
|                 <View | ||||
|                         android:layout_marginEnd="5dp" | ||||
|                         android:layout_marginTop="5dp" | ||||
|                         android:layout_marginBottom="5dp" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         android:background="@color/usedStorageColor" | ||||
|                         android:layout_width="10dp" | ||||
|                         android:layout_height="10dp"/> | ||||
|                 <TextView | ||||
|                         android:id="@+id/download_used_txt" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         tools:text="Used • 30.58GB" | ||||
|                         android:textSize="12sp" | ||||
|                         android:textColor="?attr/textColor" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content"/> | ||||
| 
 | ||||
|             <View | ||||
|                     android:layout_margin="5dp" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:background="?attr/colorPrimary" | ||||
|                     android:layout_width="10dp" | ||||
|                     android:layout_height="10dp"/> | ||||
|             <TextView | ||||
|                     android:id="@+id/download_app_txt" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     tools:text="App • 30.58GB" | ||||
|                     android:textSize="12sp" | ||||
|                     android:textColor="?attr/textColor" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content"/> | ||||
|             <View | ||||
|                     android:layout_margin="5dp" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:background="@color/freeStorageColor" | ||||
|                     android:layout_width="10dp" | ||||
|                     android:layout_height="10dp"/> | ||||
|             <TextView | ||||
|                     android:id="@+id/download_free_txt" | ||||
|                     android:textSize="12sp" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     tools:text="Free • 30.58GB" | ||||
|                     android:textColor="?attr/textColor" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content"/> | ||||
|                 <View | ||||
|                         android:layout_margin="5dp" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         android:background="?attr/colorPrimary" | ||||
|                         android:layout_width="10dp" | ||||
|                         android:layout_height="10dp"/> | ||||
|                 <TextView | ||||
|                         android:id="@+id/download_app_txt" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         tools:text="App • 30.58GB" | ||||
|                         android:textSize="12sp" | ||||
|                         android:textColor="?attr/textColor" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content"/> | ||||
|                 <View | ||||
|                         android:layout_margin="5dp" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         android:background="@color/freeStorageColor" | ||||
|                         android:layout_width="10dp" | ||||
|                         android:layout_height="10dp"/> | ||||
|                 <TextView | ||||
|                         android:id="@+id/download_free_txt" | ||||
|                         android:textSize="12sp" | ||||
|                         android:layout_gravity="center_vertical" | ||||
|                         tools:text="Free • 30.58GB" | ||||
|                         android:textColor="?attr/textColor" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content"/> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </LinearLayout> | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|             android:layout_margin="10dp" | ||||
|             android:background="?attr/bitDarkerGrayBackground" | ||||
|             app:layout_behavior="@string/appbar_scrolling_view_behavior" | ||||
|             android:padding="10dp" | ||||
|             android:id="@+id/download_list" | ||||
|             android:layout_width="match_parent" | ||||
|             tools:listitem="@layout/download_header_episode" | ||||
|             android:layout_height="wrap_content"> | ||||
|             android:layout_height="match_parent"> | ||||
|     </androidx.recyclerview.widget.RecyclerView> | ||||
|     <TextView | ||||
|             android:id="@+id/text_no_downloads" | ||||
|  | @ -115,4 +129,4 @@ | |||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" | ||||
|             app:layout_constraintBottom_toBottomOf="parent"/> | ||||
| </LinearLayout> | ||||
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | ||||
|  | @ -8,9 +8,7 @@ | |||
|         android:id="@+id/searchRoot" | ||||
|         tools:context=".ui.search.SearchFragment" | ||||
|         android:orientation="vertical" | ||||
|         android:layout_marginTop="@dimen/navbarHeight" | ||||
| 
 | ||||
|         android:background="@color/grayBackground"> | ||||
|         android:layout_marginTop="@dimen/navbarHeight"> | ||||
|     <FrameLayout android:visibility="visible" | ||||
|                  android:layout_margin="10dp" | ||||
|                  android:background="@drawable/search_background" | ||||
|  |  | |||
|  | @ -1,23 +1,22 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
| <!-- | ||||
|     <item | ||||
|             android:id="@+id/navigation_home" | ||||
|             android:icon="@drawable/ic_home_black_24dp" | ||||
|             android:title="@string/title_home"/> | ||||
| 
 | ||||
| --> | ||||
|     <item | ||||
|             android:id="@+id/navigation_search" | ||||
|             android:icon="@drawable/search_icon" | ||||
|             android:title="@string/title_search"/> | ||||
| 
 | ||||
|     <item | ||||
|             android:id="@+id/navigation_notifications" | ||||
|             android:id="@+id/navigation_downloads" | ||||
|             android:icon="@drawable/netflix_download" | ||||
|             android:title="@string/title_downloads"/> | ||||
|     <item | ||||
|             android:id="@+id/navigation_settings" | ||||
|             android:icon="@drawable/ic_outline_settings_24" | ||||
|             android:title="@string/title_settings"/> | ||||
| 
 | ||||
| </menu> | ||||
|  | @ -18,7 +18,7 @@ | |||
|             tools:layout="@layout/fragment_search"/> | ||||
| 
 | ||||
|     <fragment | ||||
|             android:id="@+id/navigation_notifications" | ||||
|             android:id="@+id/navigation_downloads" | ||||
|             android:name="com.lagradost.cloudstream3.ui.download.DownloadFragment" | ||||
|             android:label="@string/title_downloads" | ||||
|             tools:layout="@layout/fragment_downloads"/> | ||||
|  | @ -28,4 +28,11 @@ | |||
|             android:name="com.lagradost.cloudstream3.ui.settings.SettingsFragment" | ||||
|             android:label="@string/title_settings" | ||||
|     /> | ||||
| 
 | ||||
|     <fragment | ||||
|             android:id="@+id/navigation_download_child" | ||||
|             android:layout_height="match_parent" | ||||
|             android:name="com.lagradost.cloudstream3.ui.download.DownloadChildFragment" | ||||
|             android:label="@string/title_settings" | ||||
|     /> | ||||
| </navigation> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue