2021-04-30 17:20:15 +00:00
|
|
|
package com.lagradost.cloudstream3
|
|
|
|
|
2021-08-24 22:19:15 +00:00
|
|
|
import android.app.Activity
|
2021-06-10 23:00:22 +00:00
|
|
|
import android.app.PictureInPictureParams
|
2021-07-17 21:36:50 +00:00
|
|
|
import android.content.ComponentName
|
2021-07-04 00:59:51 +00:00
|
|
|
import android.content.Intent
|
2021-06-10 23:00:22 +00:00
|
|
|
import android.content.pm.PackageManager
|
2021-07-19 13:19:47 +00:00
|
|
|
import android.content.res.ColorStateList
|
2021-06-10 23:00:22 +00:00
|
|
|
import android.os.Build
|
2021-04-30 17:20:15 +00:00
|
|
|
import android.os.Bundle
|
2021-08-24 22:19:15 +00:00
|
|
|
import android.view.*
|
|
|
|
import android.widget.TextView
|
|
|
|
import android.widget.Toast
|
|
|
|
import androidx.annotation.StringRes
|
2021-04-30 17:20:15 +00:00
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
2021-07-19 13:19:47 +00:00
|
|
|
import androidx.navigation.NavOptions
|
2021-04-30 17:20:15 +00:00
|
|
|
import androidx.navigation.findNavController
|
2021-07-19 13:19:47 +00:00
|
|
|
import androidx.navigation.fragment.NavHostFragment
|
2021-06-14 00:00:29 +00:00
|
|
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
2021-08-06 20:55:11 +00:00
|
|
|
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
2021-07-30 01:14:53 +00:00
|
|
|
import com.lagradost.cloudstream3.APIHolder.apis
|
2021-07-08 19:39:49 +00:00
|
|
|
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
2021-07-30 01:14:53 +00:00
|
|
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
2021-07-19 13:19:47 +00:00
|
|
|
import com.lagradost.cloudstream3.ui.download.DownloadChildFragment
|
2021-07-30 01:14:53 +00:00
|
|
|
import com.lagradost.cloudstream3.ui.download.DownloadFragment
|
|
|
|
import com.lagradost.cloudstream3.ui.home.HomeFragment
|
|
|
|
import com.lagradost.cloudstream3.ui.search.SearchFragment
|
|
|
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
|
|
|
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
2021-07-17 15:56:26 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
2021-07-17 21:36:50 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
|
|
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
2021-07-30 23:41:54 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.Event
|
2021-08-15 17:38:41 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
2021-08-24 22:19:15 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
|
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
|
|
|
|
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
2021-07-30 01:14:53 +00:00
|
|
|
import kotlinx.android.synthetic.main.activity_main.*
|
2021-06-14 00:00:29 +00:00
|
|
|
import kotlinx.android.synthetic.main.fragment_result.*
|
2021-08-15 17:38:41 +00:00
|
|
|
import kotlin.concurrent.thread
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-08-24 22:19:15 +00:00
|
|
|
|
2021-07-17 21:36:50 +00:00
|
|
|
const val VLC_PACKAGE = "org.videolan.vlc"
|
|
|
|
const val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
|
|
|
|
val VLC_COMPONENT: ComponentName =
|
|
|
|
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
|
|
|
|
const val VLC_REQUEST_CODE = 42
|
|
|
|
|
|
|
|
const val VLC_FROM_START = -1
|
|
|
|
const val VLC_FROM_PROGRESS = -2
|
|
|
|
const val VLC_EXTRA_POSITION_OUT = "extra_position"
|
|
|
|
const val VLC_EXTRA_DURATION_OUT = "extra_duration"
|
|
|
|
const val VLC_LAST_ID_KEY = "vlc_last_open_id"
|
2021-06-14 16:58:43 +00:00
|
|
|
|
2021-08-06 20:55:11 +00:00
|
|
|
class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|
|
|
override fun onColorSelected(dialogId: Int, color: Int) {
|
|
|
|
onColorSelectedEvent.invoke(Pair(dialogId, color))
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDialogDismissed(dialogId: Int) {
|
|
|
|
onDialogDismissedEvent.invoke(dialogId)
|
|
|
|
}
|
2021-06-10 23:00:22 +00:00
|
|
|
|
|
|
|
companion object {
|
2021-08-04 01:50:24 +00:00
|
|
|
var canEnterPipMode: Boolean = false
|
2021-06-10 23:00:22 +00:00
|
|
|
var canShowPipMode: Boolean = false
|
|
|
|
var isInPIPMode: Boolean = false
|
2021-07-30 23:41:54 +00:00
|
|
|
|
|
|
|
val backEvent = Event<Boolean>()
|
2021-08-06 20:55:11 +00:00
|
|
|
val onColorSelectedEvent = Event<Pair<Int, Int>>()
|
|
|
|
val onDialogDismissedEvent = Event<Int>()
|
2021-07-19 13:19:47 +00:00
|
|
|
lateinit var navOptions: NavOptions
|
2021-08-24 22:19:15 +00:00
|
|
|
|
|
|
|
var currentToast: Toast? = null
|
2021-08-29 18:42:44 +00:00
|
|
|
|
2021-08-24 22:19:15 +00:00
|
|
|
fun showToast(act: Activity?, @StringRes message: Int, duration: Int) {
|
|
|
|
if (act == null) return
|
|
|
|
showToast(act, act.getString(message), duration)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun showToast(act: Activity?, message: String, duration: Int) {
|
|
|
|
if (act == null) return
|
|
|
|
try {
|
|
|
|
currentToast?.cancel()
|
|
|
|
} catch (e: Exception) {
|
|
|
|
e.printStackTrace()
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
val inflater = act.getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
|
|
|
|
val layout: View = inflater.inflate(
|
|
|
|
R.layout.toast,
|
|
|
|
act.findViewById<View>(R.id.toast_layout_root) as ViewGroup?
|
|
|
|
)
|
|
|
|
|
|
|
|
val text = layout.findViewById(R.id.text) as TextView
|
|
|
|
text.text = message.trim()
|
|
|
|
|
|
|
|
val toast = Toast(act)
|
|
|
|
toast.setGravity(Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, 0, 5.toPx)
|
|
|
|
toast.duration = duration
|
|
|
|
toast.view = layout
|
|
|
|
toast.show()
|
|
|
|
currentToast = toast
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2021-06-10 23:00:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun enterPIPMode() {
|
2021-08-04 01:50:24 +00:00
|
|
|
if (!shouldShowPIPMode(canEnterPipMode) || !canShowPipMode) return
|
2021-06-10 23:00:22 +00:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
try {
|
|
|
|
enterPictureInPictureMode(PictureInPictureParams.Builder().build())
|
|
|
|
} catch (e: Exception) {
|
|
|
|
enterPictureInPictureMode()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
|
enterPictureInPictureMode()
|
|
|
|
}
|
|
|
|
}
|
2021-05-22 22:25:56 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 23:00:22 +00:00
|
|
|
override fun onUserLeaveHint() {
|
|
|
|
super.onUserLeaveHint()
|
2021-08-04 01:50:24 +00:00
|
|
|
if (canEnterPipMode && canShowPipMode) {
|
2021-06-10 23:00:22 +00:00
|
|
|
enterPIPMode()
|
|
|
|
}
|
|
|
|
}
|
2021-05-22 22:25:56 +00:00
|
|
|
|
2021-05-18 13:43:32 +00:00
|
|
|
private fun AppCompatActivity.backPressed(): Boolean {
|
|
|
|
val currentFragment = supportFragmentManager.fragments.last {
|
|
|
|
it.isVisible
|
|
|
|
}
|
|
|
|
|
2021-07-19 13:19:47 +00:00
|
|
|
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
|
|
|
|
}
|
2021-07-31 22:11:56 +00:00
|
|
|
if (child is SearchFragment || child is HomeFragment || child is DownloadFragment || child is SettingsFragment) {
|
2021-07-30 01:14:53 +00:00
|
|
|
this.finish()
|
|
|
|
return true
|
|
|
|
}
|
2021-07-19 13:19:47 +00:00
|
|
|
}
|
|
|
|
|
2021-05-18 13:43:32 +00:00
|
|
|
if (currentFragment != null && supportFragmentManager.fragments.size > 2) {
|
|
|
|
//MainActivity.showNavbar()
|
|
|
|
supportFragmentManager.beginTransaction()
|
|
|
|
.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit)
|
|
|
|
.remove(currentFragment)
|
|
|
|
.commitAllowingStateLoss()
|
2021-07-30 23:41:54 +00:00
|
|
|
backEvent.invoke(true)
|
2021-05-18 13:43:32 +00:00
|
|
|
return true
|
|
|
|
}
|
2021-07-30 23:41:54 +00:00
|
|
|
backEvent.invoke(false)
|
2021-05-18 13:43:32 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onBackPressed() {
|
|
|
|
if (backPressed()) return
|
|
|
|
super.onBackPressed()
|
|
|
|
}
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-07-04 00:59:51 +00:00
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
2021-07-17 21:36:50 +00:00
|
|
|
if (VLC_REQUEST_CODE == requestCode) {
|
|
|
|
if (resultCode == RESULT_OK && data != null) {
|
|
|
|
val pos: Long =
|
|
|
|
data.getLongExtra(VLC_EXTRA_POSITION_OUT, -1) //Last position in media when player exited
|
|
|
|
val dur: Long =
|
|
|
|
data.getLongExtra(VLC_EXTRA_DURATION_OUT, -1) //Last position in media when player exited
|
|
|
|
val id = getKey<Int>(VLC_LAST_ID_KEY)
|
2021-07-18 13:02:30 +00:00
|
|
|
println("SET KEY $id at $pos / $dur")
|
2021-07-17 21:36:50 +00:00
|
|
|
if (dur > 0 && pos > 0) {
|
|
|
|
setViewPos(id, pos, dur)
|
|
|
|
}
|
|
|
|
removeKey(VLC_LAST_ID_KEY)
|
|
|
|
}
|
|
|
|
}
|
2021-07-04 00:59:51 +00:00
|
|
|
super.onActivityResult(requestCode, resultCode, data)
|
|
|
|
}
|
|
|
|
|
2021-07-08 17:46:47 +00:00
|
|
|
override fun onDestroy() {
|
|
|
|
val broadcastIntent = Intent()
|
|
|
|
broadcastIntent.action = "restart_service"
|
|
|
|
broadcastIntent.setClass(this, VideoDownloadRestartReceiver::class.java)
|
|
|
|
this.sendBroadcast(broadcastIntent)
|
|
|
|
super.onDestroy()
|
|
|
|
}
|
|
|
|
|
2021-07-30 01:14:53 +00:00
|
|
|
override fun onNewIntent(intent: Intent?) {
|
|
|
|
handleAppIntent(intent)
|
|
|
|
super.onNewIntent(intent)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun handleAppIntent(intent: Intent?) {
|
|
|
|
if (intent == null) return
|
|
|
|
val str = intent.dataString
|
|
|
|
if (str != null) {
|
|
|
|
if (str.startsWith(DOWNLOAD_NAVIGATE_TO)) {
|
|
|
|
findNavController(R.id.nav_host_fragment).navigate(R.id.navigation_downloads, null, navOptions)
|
|
|
|
} else {
|
|
|
|
for (api in apis) {
|
|
|
|
if (str.startsWith(api.mainUrl)) {
|
2021-07-30 14:09:57 +00:00
|
|
|
loadResult(str, api.name)
|
2021-07-30 01:14:53 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
2021-08-14 17:42:47 +00:00
|
|
|
theme.applyStyle(
|
|
|
|
R.style.LoadedStyle,
|
|
|
|
true
|
|
|
|
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
super.onCreate(savedInstanceState)
|
2021-07-30 01:14:53 +00:00
|
|
|
|
2021-07-28 01:04:32 +00:00
|
|
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
2021-06-29 23:14:48 +00:00
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
setContentView(R.layout.activity_main)
|
2021-07-30 01:14:53 +00:00
|
|
|
// val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-06-10 23:00:22 +00:00
|
|
|
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
|
|
|
|
//https://developer.android.com/guide/topics/ui/picture-in-picture
|
|
|
|
canShowPipMode =
|
|
|
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && // OS SUPPORT
|
|
|
|
packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && // HAS FEATURE, MIGHT BE BLOCKED DUE TO POWER DRAIN
|
|
|
|
hasPIPPermission() // CHECK IF FEATURE IS ENABLED IN SETTINGS
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
val navController = findNavController(R.id.nav_host_fragment)
|
2021-07-19 13:19:47 +00:00
|
|
|
|
|
|
|
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()
|
|
|
|
|
2021-07-30 01:14:53 +00:00
|
|
|
nav_view.setOnNavigationItemSelectedListener { item ->
|
2021-07-19 13:19:47 +00:00
|
|
|
when (item.itemId) {
|
2021-07-28 01:04:32 +00:00
|
|
|
R.id.navigation_home -> {
|
|
|
|
navController.navigate(R.id.navigation_home, null, navOptions)
|
|
|
|
}
|
2021-07-19 13:19:47 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-07-30 01:14:53 +00:00
|
|
|
nav_view.itemRippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f))
|
2021-05-20 21:25:41 +00:00
|
|
|
|
|
|
|
if (!checkWrite()) {
|
|
|
|
requestRW()
|
|
|
|
if (checkWrite()) return
|
|
|
|
}
|
2021-06-14 00:00:29 +00:00
|
|
|
CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
|
2021-06-14 16:58:43 +00:00
|
|
|
|
2021-07-15 16:45:25 +00:00
|
|
|
// THIS IS CURRENTLY REMOVED BECAUSE HIGHER VERS OF ANDROID NEEDS A NOTIFICATION
|
|
|
|
//if (!VideoDownloadManager.isMyServiceRunning(this, VideoDownloadKeepAliveService::class.java)) {
|
|
|
|
// val mYourService = VideoDownloadKeepAliveService()
|
|
|
|
// val mServiceIntent = Intent(this, mYourService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE)
|
|
|
|
// this.startService(mServiceIntent)
|
|
|
|
//}
|
2021-07-17 15:56:26 +00:00
|
|
|
//settingsManager.getBoolean("disable_automatic_data_downloads", true) &&
|
2021-07-25 14:25:09 +00:00
|
|
|
|
|
|
|
// TODO RETURN TO TRUE
|
|
|
|
/*
|
2021-07-17 21:36:50 +00:00
|
|
|
if (isUsingMobileData()) {
|
2021-07-17 15:56:26 +00:00
|
|
|
Toast.makeText(this, "Downloads not resumed on mobile data", Toast.LENGTH_LONG).show()
|
|
|
|
} else {
|
|
|
|
val keys = getKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)
|
|
|
|
val resumePkg = keys.mapNotNull { k -> getKey<VideoDownloadManager.DownloadResumePackage>(k) }
|
|
|
|
|
|
|
|
// To remove a bug where this is permanent
|
|
|
|
removeKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)
|
|
|
|
|
|
|
|
for (pkg in resumePkg) { // ADD ALL CURRENT DOWNLOADS
|
|
|
|
VideoDownloadManager.downloadFromResume(this, pkg, false)
|
|
|
|
}
|
2021-07-08 17:46:47 +00:00
|
|
|
|
2021-07-17 15:56:26 +00:00
|
|
|
// ADD QUEUE
|
|
|
|
// array needed because List gets cast exception to linkedList for some unknown reason
|
|
|
|
val resumeQueue =
|
|
|
|
getKey<Array<VideoDownloadManager.DownloadQueueResumePackage>>(VideoDownloadManager.KEY_RESUME_QUEUE_PACKAGES)
|
|
|
|
|
|
|
|
resumeQueue?.sortedBy { it.index }?.forEach {
|
|
|
|
VideoDownloadManager.downloadFromResume(this, it.pkg)
|
|
|
|
}
|
2021-07-25 14:25:09 +00:00
|
|
|
}*/
|
|
|
|
|
|
|
|
|
2021-06-14 00:00:29 +00:00
|
|
|
/*
|
|
|
|
val castContext = CastContext.getSharedInstance(applicationContext)
|
|
|
|
fun buildMediaQueueItem(video: String): MediaQueueItem {
|
|
|
|
// val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO)
|
|
|
|
//movieMetadata.putString(MediaMetadata.KEY_TITLE, "CloudStream")
|
|
|
|
val mediaInfo = MediaInfo.Builder(Uri.parse(video).toString())
|
|
|
|
.setStreamType(MediaInfo.STREAM_TYPE_NONE)
|
|
|
|
.setContentType(MimeTypes.IMAGE_JPEG)
|
|
|
|
// .setMetadata(movieMetadata).build()
|
|
|
|
.build()
|
|
|
|
return MediaQueueItem.Builder(mediaInfo).build()
|
|
|
|
}*/
|
|
|
|
/*
|
|
|
|
castContext.addCastStateListener { state ->
|
|
|
|
if (state == CastState.CONNECTED) {
|
|
|
|
println("TESTING")
|
|
|
|
val isCasting = castContext?.sessionManager?.currentCastSession?.remoteMediaClient?.currentItem != null
|
|
|
|
if(!isCasting) {
|
|
|
|
val castPlayer = CastPlayer(castContext)
|
|
|
|
println("LOAD ITEM")
|
|
|
|
|
|
|
|
castPlayer.loadItem(buildMediaQueueItem("https://cdn.discordapp.com/attachments/551382684560261121/730169809408622702/ChromecastLogo6.png"),0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}*/
|
2021-07-31 22:11:56 +00:00
|
|
|
/*thread {
|
|
|
|
createISO()
|
|
|
|
}*/
|
2021-08-19 20:05:18 +00:00
|
|
|
|
|
|
|
var providersString = "Current providers are:\n"
|
|
|
|
for (api in apis) {
|
|
|
|
providersString += "+ ${api.mainUrl}\n"
|
|
|
|
}
|
|
|
|
println(providersString)
|
|
|
|
|
2021-07-30 01:14:53 +00:00
|
|
|
handleAppIntent(intent)
|
2021-08-15 17:38:41 +00:00
|
|
|
|
|
|
|
thread {
|
|
|
|
runAutoUpdate()
|
|
|
|
}
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
2021-08-06 20:55:11 +00:00
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|