forked from recloudstream/cloudstream
lots of chromecast stuff for better UI
This commit is contained in:
parent
ac442edd4e
commit
6579eb3083
12 changed files with 207 additions and 66 deletions
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3
|
|||
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
|
@ -12,10 +13,20 @@ import androidx.lifecycle.ViewModelStoreOwner
|
|||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.google.android.exoplayer2.ext.cast.CastPlayer
|
||||
import com.google.android.exoplayer2.util.MimeTypes
|
||||
import com.google.android.gms.cast.MediaInfo
|
||||
import com.google.android.gms.cast.MediaMetadata
|
||||
import com.google.android.gms.cast.MediaQueueItem
|
||||
import com.google.android.gms.cast.MediaStatus
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.cast.framework.CastState
|
||||
import com.lagradost.cloudstream3.UIHelper.checkWrite
|
||||
import com.lagradost.cloudstream3.UIHelper.hasPIPPermission
|
||||
import com.lagradost.cloudstream3.UIHelper.requestRW
|
||||
import com.lagradost.cloudstream3.UIHelper.shouldShowPIPMode
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
/*, ViewModelStoreOwner {
|
||||
|
@ -99,5 +110,32 @@ class MainActivity : AppCompatActivity() {
|
|||
requestRW()
|
||||
if (checkWrite()) return
|
||||
}
|
||||
|
||||
CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
|
||||
/*
|
||||
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)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import android.app.AppOpsManager
|
|||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
|
@ -13,6 +14,7 @@ import android.os.Build
|
|||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -21,9 +23,10 @@ import androidx.preference.PreferenceManager
|
|||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.lagradost.cloudstream3.UIHelper.getGridFormat
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
object UIHelper {
|
||||
val Int.toPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
|
||||
|
@ -143,6 +146,21 @@ object UIHelper {
|
|||
return isCastApiAvailable
|
||||
}
|
||||
|
||||
fun adjustAlpha(@ColorInt color: Int, factor: Float): Int {
|
||||
val alpha = (Color.alpha(color) * factor).roundToInt()
|
||||
val red = Color.red(color)
|
||||
val green = Color.green(color)
|
||||
val blue = Color.blue(color)
|
||||
return Color.argb(alpha, red, green, blue)
|
||||
}
|
||||
|
||||
fun Context.colorFromAttribute(attribute: Int): Int {
|
||||
val attributes = obtainStyledAttributes(intArrayOf(attribute))
|
||||
val color = attributes.getColor(0, 0)
|
||||
attributes.recycle()
|
||||
return color
|
||||
}
|
||||
|
||||
fun getFocusRequest(): AudioFocusRequest? {
|
||||
if (_AudioFocusRequest != null) return _AudioFocusRequest
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
|
|
|
@ -6,14 +6,22 @@ import android.view.View.INVISIBLE
|
|||
import android.view.View.VISIBLE
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
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.gms.cast.MediaStatus.REPEAT_MODE_REPEAT_SINGLE
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import com.google.android.gms.cast.framework.media.uicontroller.UIController
|
||||
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.UIHelper.hideSystemUI
|
||||
import com.lagradost.cloudstream3.utils.Coroutines
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.lang.Exception
|
||||
|
||||
class SkipOpController(val view: ImageView) : UIController() {
|
||||
init {
|
||||
|
@ -24,7 +32,12 @@ class SkipOpController(val view: ImageView) : UIController() {
|
|||
}
|
||||
}
|
||||
|
||||
class SelectSourceController(val view: ImageView) : UIController() {
|
||||
data class MetadataSource(val name: String)
|
||||
data class MetadataHolder(val data: List<MetadataSource>)
|
||||
|
||||
class SelectSourceController(val view: ImageView, val activity: ControllerActivity) : UIController() {
|
||||
private val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule())
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()
|
||||
|
||||
init {
|
||||
view.setImageResource(R.drawable.ic_baseline_playlist_play_24)
|
||||
|
@ -33,31 +46,28 @@ class SelectSourceController(val view: ImageView) : UIController() {
|
|||
//println(remoteMediaClient.mediaInfo.customData)
|
||||
//remoteMediaClient.queueJumpToItem()
|
||||
lateinit var dialog: AlertDialog
|
||||
val items = mutableListOf<Pair<Int, String>>()
|
||||
for (i in 0 until remoteMediaClient.mediaQueue.itemCount) {
|
||||
(remoteMediaClient.mediaQueue.getItemAtIndex(i)?.media?.customData?.get("data") as? String)?.let { name ->
|
||||
items.add(
|
||||
remoteMediaClient.mediaQueue.getItemAtIndex(i)!!.itemId to name
|
||||
)
|
||||
}
|
||||
}
|
||||
val holder = getCurrentMetaData()
|
||||
|
||||
// TODO FIX
|
||||
if (items.isNotEmpty()) {
|
||||
if (holder != null) {
|
||||
val items = holder.data
|
||||
if (items.isNotEmpty() && remoteMediaClient.currentItem != null) {
|
||||
val builder = AlertDialog.Builder(view.context, R.style.AlertDialogCustom)
|
||||
builder.setTitle("Pick source")
|
||||
|
||||
builder.setSingleChoiceItems(
|
||||
items.map { it.second }.toTypedArray(),
|
||||
remoteMediaClient.currentItem.itemId - 1
|
||||
items.map { it.name }.toTypedArray(),
|
||||
remoteMediaClient.mediaQueue.indexOfItemWithId(remoteMediaClient.currentItem.itemId)
|
||||
) { _, which ->
|
||||
println(
|
||||
val itemId = remoteMediaClient.mediaQueue.itemIds?.get(which)
|
||||
|
||||
itemId?.let { id ->
|
||||
remoteMediaClient.queueJumpToItem(
|
||||
items[which].first,
|
||||
id,
|
||||
remoteMediaClient.approximateStreamPosition,
|
||||
null
|
||||
)
|
||||
remoteMediaClient.mediaInfo.customData
|
||||
)
|
||||
}
|
||||
|
||||
dialog.dismiss()
|
||||
}
|
||||
dialog = builder.create()
|
||||
|
@ -65,13 +75,23 @@ class SelectSourceController(val view: ImageView) : UIController() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentMetaData(): MetadataHolder? {
|
||||
return try {
|
||||
val data = remoteMediaClient.mediaInfo.customData
|
||||
mapper.readValue<MetadataHolder>(data.toString())
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMediaStatusUpdated() {
|
||||
super.onMediaStatusUpdated()
|
||||
// If there's 1 item it won't show
|
||||
val dataString = remoteMediaClient.mediaQueue.getItemAtIndex(1)?.media?.customData?.get("data") as? String
|
||||
|
||||
view.visibility = if (dataString != null) VISIBLE else INVISIBLE
|
||||
view.visibility =
|
||||
if ((getCurrentMetaData()?.data?.size
|
||||
?: 0) > 1
|
||||
) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun onSessionConnected(castSession: CastSession?) {
|
||||
|
@ -107,7 +127,7 @@ class ControllerActivity : ExpandedControllerActivity() {
|
|||
val skipBackButton: ImageView = getButtonImageViewAt(1)
|
||||
val skipForwardButton: ImageView = getButtonImageViewAt(2)
|
||||
val skipOpButton: ImageView = getButtonImageViewAt(3)
|
||||
uiMediaController.bindViewToUIController(sourcesButton, SelectSourceController(sourcesButton))
|
||||
uiMediaController.bindViewToUIController(sourcesButton, SelectSourceController(sourcesButton, this))
|
||||
uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false))
|
||||
uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true))
|
||||
uiMediaController.bindViewToUIController(skipOpButton, SkipOpController(skipOpButton))
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.lagradost.cloudstream3.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.RelativeLayout
|
||||
import com.google.android.gms.cast.framework.media.widget.MiniControllerFragment
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.UIHelper.adjustAlpha
|
||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||
import com.lagradost.cloudstream3.UIHelper.toPx
|
||||
|
||||
class MyMiniControllerFragment : MiniControllerFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// SEE https://github.com/dandar3/android-google-play-services-cast-framework/blob/master/res/layout/cast_mini_controller.xml
|
||||
try {
|
||||
val progressBar: ProgressBar? = view.findViewById(R.id.progressBar)
|
||||
val containerAll: LinearLayout? = view.findViewById(R.id.container_all)
|
||||
|
||||
context?.let { ctx ->
|
||||
progressBar?.setBackgroundColor(adjustAlpha(ctx.colorFromAttribute(R.attr.colorPrimary), 0.35f))
|
||||
val params = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 2.toPx)
|
||||
|
||||
progressBar?.layoutParams = params
|
||||
}
|
||||
val child = containerAll?.getChildAt(0)
|
||||
child?.alpha = 0f // REMOVE GRADIENT
|
||||
|
||||
} catch (e: Exception) {
|
||||
// JUST IN CASE
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,6 +84,7 @@ 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 org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
@ -608,6 +609,7 @@ class PlayerFragment : Fragment() {
|
|||
private var allEpisodes: HashMap<Int, ArrayList<ExtractorLink>> = HashMap()
|
||||
private var episodes: ArrayList<ResultEpisode> = ArrayList()
|
||||
var currentPoster: String? = null
|
||||
var currentHeaderName: String? = null
|
||||
|
||||
//region PIP MODE
|
||||
private fun getPen(code: PlayerEventType): PendingIntent {
|
||||
|
@ -717,7 +719,7 @@ class PlayerFragment : Fragment() {
|
|||
|
||||
if (activity?.isCastApiAvailable() == true) {
|
||||
CastButtonFactory.setUpMediaRouteButton(activity, player_media_route_button)
|
||||
val castContext = CastContext.getSharedInstance(requireActivity().applicationContext)
|
||||
val castContext = CastContext.getSharedInstance(requireContext())
|
||||
|
||||
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) player_media_route_button.visibility = VISIBLE
|
||||
castContext.addCastStateListener { state ->
|
||||
|
@ -732,20 +734,22 @@ class PlayerFragment : Fragment() {
|
|||
|
||||
val index = links.indexOf(getCurrentUrl())
|
||||
|
||||
val customData =
|
||||
links.map { JSONObject().put("name", it.name) }
|
||||
val jsonArray = JSONArray()
|
||||
for (item in customData) {
|
||||
jsonArray.put(item)
|
||||
}
|
||||
|
||||
val mediaItems = links.map {
|
||||
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
||||
movieMetadata.putString(
|
||||
MediaMetadata.KEY_TITLE,
|
||||
|
||||
"Episode ${epData.episode}" +
|
||||
if (epData.name != null)
|
||||
"- ${epData.name}"
|
||||
else
|
||||
""
|
||||
)
|
||||
movieMetadata.putString(MediaMetadata.KEY_ALBUM_ARTIST,
|
||||
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
||||
epData.name ?: "Episode ${epData.episode}")
|
||||
|
||||
if (currentHeaderName != null)
|
||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, currentHeaderName)
|
||||
|
||||
val srcPoster = epData.poster ?: currentPoster
|
||||
if (srcPoster != null) {
|
||||
movieMetadata.addImage(WebImage(Uri.parse(srcPoster)))
|
||||
|
@ -755,7 +759,8 @@ class PlayerFragment : Fragment() {
|
|||
MediaInfo.Builder(it.url)
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setContentType(MimeTypes.VIDEO_UNKNOWN)
|
||||
.setCustomData(JSONObject().put("data", it.name))
|
||||
|
||||
.setCustomData(JSONObject().put("data", jsonArray))
|
||||
.setMetadata(movieMetadata)
|
||||
.build()
|
||||
)
|
||||
|
@ -838,6 +843,7 @@ class PlayerFragment : Fragment() {
|
|||
if (d is LoadResponse) {
|
||||
localData = d
|
||||
currentPoster = d.posterUrl
|
||||
currentHeaderName = d.name
|
||||
}
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
@ -16,7 +15,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.mediarouter.app.MediaRouteButton
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
|
@ -33,6 +31,7 @@ import com.google.android.gms.cast.framework.CastContext
|
|||
import com.google.android.gms.cast.framework.CastState
|
||||
import com.google.android.gms.common.images.WebImage
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
|
@ -42,9 +41,9 @@ import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import android.app.ProgressDialog
|
||||
import com.lagradost.cloudstream3.*
|
||||
|
||||
|
||||
const val MAX_SYNO_LENGH = 300
|
||||
|
||||
|
@ -80,6 +79,7 @@ class ResultFragment : Fragment() {
|
|||
|
||||
private lateinit var viewModel: ResultViewModel
|
||||
private var allEpisodes: HashMap<Int, ArrayList<ExtractorLink>> = HashMap()
|
||||
var currentHeaderName: String? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -157,7 +157,7 @@ class ResultFragment : Fragment() {
|
|||
//dialog.show()
|
||||
Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show()
|
||||
|
||||
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
||||
viewModel.loadEpisode(episodeClick.data, false) { data ->
|
||||
// dialog.dismiss()
|
||||
when (data) {
|
||||
is Resource.Failure -> {
|
||||
|
@ -169,30 +169,30 @@ class ResultFragment : Fragment() {
|
|||
|
||||
val castContext = CastContext.getSharedInstance(requireContext())
|
||||
|
||||
val customData =
|
||||
links.map { JSONObject().put("name", it.name) }
|
||||
val jsonArray = JSONArray()
|
||||
for (item in customData) {
|
||||
jsonArray.put(item)
|
||||
}
|
||||
|
||||
val mediaItems = links.map {
|
||||
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
||||
movieMetadata.putString(
|
||||
MediaMetadata.KEY_TITLE,
|
||||
|
||||
"Episode ${epData.episode}" +
|
||||
if (epData.name != null)
|
||||
"- ${epData.name}"
|
||||
else
|
||||
""
|
||||
)
|
||||
movieMetadata.putString(MediaMetadata.KEY_ALBUM_ARTIST,
|
||||
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
||||
epData.name ?: "Episode ${epData.episode}")
|
||||
|
||||
if (currentHeaderName != null)
|
||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, currentHeaderName)
|
||||
|
||||
val srcPoster = epData.poster ?: currentPoster
|
||||
if (srcPoster != null) {
|
||||
movieMetadata.addImage(WebImage(Uri.parse(srcPoster)))
|
||||
}
|
||||
|
||||
MediaQueueItem.Builder(
|
||||
MediaInfo.Builder(it.url)
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setContentType(MimeTypes.VIDEO_UNKNOWN)
|
||||
.setCustomData(JSONObject().put("data", it.name))
|
||||
.setCustomData(JSONObject().put("data", jsonArray))
|
||||
.setMetadata(movieMetadata)
|
||||
.build()
|
||||
)
|
||||
|
@ -255,6 +255,8 @@ class ResultFragment : Fragment() {
|
|||
if (d is LoadResponse) {
|
||||
result_bookmark_button.text = "Watching"
|
||||
|
||||
currentHeaderName = d.name
|
||||
|
||||
currentPoster = d.posterUrl
|
||||
|
||||
result_openinbrower.setOnClickListener {
|
||||
|
|
|
@ -38,7 +38,8 @@ class CastOptionsProvider : OptionsProvider {
|
|||
|
||||
return CastOptions.Builder()
|
||||
.setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)
|
||||
//.setReceiverApplicationId("C0868879") // C0868879 = SAMPLE, CHANGE TO A NICE ID at https://developers.google.com/cast/docs/registration
|
||||
//.setReceiverApplicationId("")
|
||||
// C0868879 = SAMPLE, CHANGE TO A NICE ID at https://developers.google.com/cast/docs/registration
|
||||
.setStopReceiverApplicationWhenEndingSession(true)
|
||||
.setCastMediaOptions(mediaOptions)
|
||||
.build()
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object Coroutines {
|
||||
fun main(work: suspend (() -> Unit)) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
work()
|
||||
}
|
||||
}
|
||||
}
|
4
app/src/main/res/drawable/solid_primary.xml
Normal file
4
app/src/main/res/drawable/solid_primary.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?attr/colorPrimary"/>
|
||||
</shape>
|
|
@ -42,13 +42,14 @@
|
|||
app:layout_constraintBottom_toTopOf="@+id/nav_view"
|
||||
android:id="@+id/cast_mini_controller_holder"
|
||||
>
|
||||
<!--com.google.android.gms.cast.framework.media.widget.MiniControllerFragment-->
|
||||
<fragment
|
||||
app:castControlButtons="@array/cast_mini_controller_control_buttons"
|
||||
android:id="@+id/cast_mini_controller"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"
|
||||
class="com.lagradost.cloudstream3.ui.MyMiniControllerFragment"
|
||||
tools:ignore="FragmentTagUsage">
|
||||
</fragment>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -229,7 +229,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"
|
||||
class="com.lagradost.cloudstream3.ui.MyMiniControllerFragment"
|
||||
tools:ignore="FragmentTagUsage">
|
||||
</fragment>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
<item name="tabMode">scrollable</item>
|
||||
</style>
|
||||
<style name="AlertDialogCustom" parent="Theme.AppCompat.Dialog.Alert">
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorPrimary">@color/textColor</item>
|
||||
<!--<item name="android:background">@color/darkBackground</item>-->
|
||||
|
|
Loading…
Reference in a new issue