mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Player v2 (#401)
This commit is contained in:
parent
cb65299e57
commit
9fd237301e
94 changed files with 5997 additions and 4025 deletions
|
@ -19,4 +19,4 @@
|
|||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="app/src/main/res/layout/fragment_result.xml" value="0.75" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
|
||||
</project>
|
28
app/src/debug/res/drawable-hdpi/pause_to_play.xml
Normal file
28
app/src/debug/res/drawable-hdpi/pause_to_play.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<animated-vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="850dp"
|
||||
android:height="850dp"
|
||||
android:viewportWidth="850"
|
||||
android:viewportHeight="850">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 267.01 189.64 L 366.75 189.64 L 366.75 659.9 L 267.01 659.9 Z M 463.01 188.79 L 562.75 188.79 L 562.75 659.05 L 463.01 659.05 Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="200"
|
||||
android:valueFrom="M 463.01 659.05 L 562.75 659.05 L 562.75 188.79 L 463.01 188.79 L 463.01 659.05 M 366.75 189.64 L 366.75 659.9 L 267.01 659.9 L 267.01 189.64 L 366.75 189.64"
|
||||
android:valueTo="M 425.844 568.243 L 674.6 424.6 L 551.156 353.317 L 427.712 282.035 L 425.844 568.243 M 427.712 282.035 L 425.844 568.243 L 256.9 665.8 L 256.9 183.4 L 427.712 282.035"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
28
app/src/debug/res/drawable-hdpi/play_to_pause.xml
Normal file
28
app/src/debug/res/drawable-hdpi/play_to_pause.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<animated-vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="850dp"
|
||||
android:height="850dp"
|
||||
android:viewportWidth="850"
|
||||
android:viewportHeight="850">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 674.6 424.6 L 256.9 183.4 L 256.9 665.8 Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="200"
|
||||
android:valueFrom="M 425.844 568.243 L 674.6 424.6 L 551.156 353.317 L 427.712 282.035 L 425.844 568.243 M 427.712 282.035 L 425.844 568.243 L 256.9 665.8 L 256.9 183.4 L 427.712 282.035"
|
||||
android:valueTo="M 463.01 659.05 L 562.75 659.05 L 562.75 188.79 L 463.01 188.79 L 463.01 659.05 M 366.75 189.64 L 366.75 659.9 L 267.01 659.9 L 267.01 189.64 L 366.75 189.64"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -24,10 +24,27 @@
|
|||
android:usesCleartextTraffic="true"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme" android:fullBackupContent="@xml/backup_descriptor" tools:targetApi="m">
|
||||
android:theme="@style/AppTheme"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
tools:targetApi="m">
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="com.lagradost.cloudstream3.utils.CastOptionsProvider"/>
|
||||
|
||||
<activity android:name=".ui.player.DownloadedPlayerActivity"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:mimeType="video/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:name=".MainActivity"
|
||||
|
|
353
app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt
Normal file
353
app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt
Normal file
|
@ -0,0 +1,353 @@
|
|||
package com.lagradost.cloudstream3
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import com.lagradost.cloudstream3.utils.UIHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
import java.util.*
|
||||
|
||||
object CommonActivity {
|
||||
fun Activity?.getCastSession(): CastSession? {
|
||||
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
||||
}
|
||||
|
||||
var canEnterPipMode: Boolean = false
|
||||
var canShowPipMode: Boolean = false
|
||||
var isInPIPMode: Boolean = false
|
||||
|
||||
val backEvent = Event<Boolean>()
|
||||
val onColorSelectedEvent = Event<Pair<Int, Int>>()
|
||||
val onDialogDismissedEvent = Event<Int>()
|
||||
|
||||
var playerEventListener: ((PlayerEventType) -> Unit)? = null
|
||||
var keyEventListener: ((KeyEvent?) -> Boolean)? = null
|
||||
|
||||
|
||||
var currentToast: Toast? = null
|
||||
|
||||
fun showToast(act: Activity?, @StringRes message: Int, duration: Int) {
|
||||
if (act == null) return
|
||||
showToast(act, act.getString(message), duration)
|
||||
}
|
||||
|
||||
/** duration is Toast.LENGTH_SHORT if null*/
|
||||
fun showToast(act: Activity?, message: String?, duration: Int? = null) {
|
||||
if (act == null || message == null) return
|
||||
try {
|
||||
currentToast?.cancel()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
try {
|
||||
val inflater =
|
||||
act.getSystemService(AppCompatActivity.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.LENGTH_SHORT
|
||||
toast.view = layout
|
||||
toast.show()
|
||||
currentToast = toast
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun setLocale(context: Context?, languageCode: String?) {
|
||||
if (context == null || languageCode == null) return
|
||||
val locale = Locale(languageCode)
|
||||
val resources: Resources = context.resources
|
||||
val config = resources.configuration
|
||||
Locale.setDefault(locale)
|
||||
config.setLocale(locale)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
context.createConfigurationContext(config)
|
||||
resources.updateConfiguration(config, resources.displayMetrics)
|
||||
}
|
||||
|
||||
fun Context.updateLocale() {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val localeCode = settingsManager.getString(getString(R.string.locale_key), null)
|
||||
setLocale(this, localeCode)
|
||||
}
|
||||
|
||||
fun init(act: Activity?) {
|
||||
if (act == null) return
|
||||
//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
|
||||
act.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && // HAS FEATURE, MIGHT BE BLOCKED DUE TO POWER DRAIN
|
||||
act.hasPIPPermission() // CHECK IF FEATURE IS ENABLED IN SETTINGS
|
||||
|
||||
act.updateLocale()
|
||||
}
|
||||
|
||||
private fun Activity.enterPIPMode() {
|
||||
if (!shouldShowPIPMode(canEnterPipMode) || !canShowPipMode) return
|
||||
try {
|
||||
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()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun onUserLeaveHint(act: Activity?) {
|
||||
if (canEnterPipMode && canShowPipMode) {
|
||||
act?.enterPIPMode()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadThemes(act: Activity? ) {
|
||||
if(act == null) return
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(act)
|
||||
|
||||
val currentTheme =
|
||||
when (settingsManager.getString(act.getString(R.string.app_theme_key), "AmoledLight")) {
|
||||
"Black" -> R.style.AppTheme
|
||||
"Light" -> R.style.LightMode
|
||||
"Amoled" -> R.style.AmoledMode
|
||||
"AmoledLight" -> R.style.AmoledModeLight
|
||||
else -> R.style.AppTheme
|
||||
}
|
||||
|
||||
val currentOverlayTheme =
|
||||
when (settingsManager.getString(act.getString(R.string.primary_color_key), "Normal")) {
|
||||
"Normal" -> R.style.OverlayPrimaryColorNormal
|
||||
"Blue" -> R.style.OverlayPrimaryColorBlue
|
||||
"Purple" -> R.style.OverlayPrimaryColorPurple
|
||||
"Green" -> R.style.OverlayPrimaryColorGreen
|
||||
"GreenApple" -> R.style.OverlayPrimaryColorGreenApple
|
||||
"Red" -> R.style.OverlayPrimaryColorRed
|
||||
"Banana" -> R.style.OverlayPrimaryColorBanana
|
||||
"Party" -> R.style.OverlayPrimaryColorParty
|
||||
"Pink" -> R.style.OverlayPrimaryColorPink
|
||||
else -> R.style.OverlayPrimaryColorNormal
|
||||
}
|
||||
act.theme.applyStyle(currentTheme, true)
|
||||
act.theme.applyStyle(currentOverlayTheme, true)
|
||||
|
||||
act.theme.applyStyle(
|
||||
R.style.LoadedStyle,
|
||||
true
|
||||
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
|
||||
}
|
||||
|
||||
private fun getNextFocus(
|
||||
act: Activity?,
|
||||
view: View?,
|
||||
direction: FocusDirection,
|
||||
depth: Int = 0
|
||||
): Int? {
|
||||
if (view == null || depth >= 10 || act == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nextId = when (direction) {
|
||||
FocusDirection.Left -> {
|
||||
view.nextFocusLeftId
|
||||
}
|
||||
FocusDirection.Up -> {
|
||||
view.nextFocusUpId
|
||||
}
|
||||
FocusDirection.Right -> {
|
||||
view.nextFocusRightId
|
||||
}
|
||||
FocusDirection.Down -> {
|
||||
view.nextFocusDownId
|
||||
}
|
||||
}
|
||||
|
||||
return if (nextId != -1) {
|
||||
val next = act.findViewById<View?>(nextId)
|
||||
//println("NAME: ${next.accessibilityClassName} | ${next?.isShown}" )
|
||||
|
||||
if (next?.isShown == false) {
|
||||
getNextFocus(act, next, direction, depth + 1)
|
||||
} else {
|
||||
if (depth == 0) {
|
||||
null
|
||||
} else {
|
||||
nextId
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
enum class FocusDirection {
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
fun onKeyDown(act: Activity?, keyCode: Int, event: KeyEvent?) {
|
||||
//println("Keycode: $keyCode")
|
||||
//showToast(
|
||||
// this,
|
||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
||||
// Toast.LENGTH_LONG
|
||||
//)
|
||||
|
||||
// Tested keycodes on remote:
|
||||
// KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
||||
// KeyEvent.KEYCODE_MEDIA_REWIND
|
||||
// KeyEvent.KEYCODE_MENU
|
||||
// KeyEvent.KEYCODE_MEDIA_NEXT
|
||||
// KeyEvent.KEYCODE_MEDIA_PREVIOUS
|
||||
// KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|
||||
|
||||
// 149 keycode_numpad 5
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {
|
||||
PlayerEventType.SeekForward
|
||||
}
|
||||
KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
|
||||
PlayerEventType.SeekBack
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1 -> {
|
||||
PlayerEventType.NextEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1 -> {
|
||||
PlayerEventType.PrevEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
||||
PlayerEventType.Pause
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> {
|
||||
PlayerEventType.Play
|
||||
}
|
||||
KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7 -> {
|
||||
PlayerEventType.Lock
|
||||
}
|
||||
KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> {
|
||||
PlayerEventType.ToggleHide
|
||||
}
|
||||
KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> {
|
||||
PlayerEventType.ToggleMute
|
||||
}
|
||||
KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9 -> {
|
||||
PlayerEventType.ShowMirrors
|
||||
}
|
||||
KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3 -> {
|
||||
PlayerEventType.ShowSpeed
|
||||
}
|
||||
KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0 -> {
|
||||
PlayerEventType.Resize
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation
|
||||
PlayerEventType.PlayPauseToggle
|
||||
}
|
||||
else -> null
|
||||
}?.let { playerEvent ->
|
||||
playerEventListener?.invoke(playerEvent)
|
||||
}
|
||||
|
||||
//when (keyCode) {
|
||||
// KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
// println("DPAD PRESSED")
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
fun dispatchKeyEvent(act: Activity?, event: KeyEvent?): Boolean? {
|
||||
if (act == null) return null
|
||||
event?.keyCode?.let { keyCode ->
|
||||
when (event.action) {
|
||||
KeyEvent.ACTION_DOWN -> {
|
||||
if (act.currentFocus != null) {
|
||||
val next = when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(
|
||||
act,
|
||||
act.currentFocus,
|
||||
FocusDirection.Left
|
||||
)
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
|
||||
act,
|
||||
act.currentFocus,
|
||||
FocusDirection.Right
|
||||
)
|
||||
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
|
||||
act,
|
||||
act.currentFocus,
|
||||
FocusDirection.Up
|
||||
)
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
|
||||
act,
|
||||
act.currentFocus,
|
||||
FocusDirection.Down
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (next != null && next != -1) {
|
||||
val nextView = act.findViewById<View?>(next)
|
||||
if (nextView != null) {
|
||||
nextView.requestFocus()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
if (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete) {
|
||||
UIHelper.showInputMethod(act.currentFocus?.findFocus())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//println("Keycode: $keyCode")
|
||||
//showToast(
|
||||
// this,
|
||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
||||
// Toast.LENGTH_LONG
|
||||
//)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyEventListener?.invoke(event) == true) {
|
||||
return true
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
|
|||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import com.lagradost.cloudstream3.animeproviders.*
|
||||
import com.lagradost.cloudstream3.movieproviders.*
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import java.util.*
|
||||
|
||||
|
@ -298,18 +299,12 @@ fun MainAPI.fixUrl(url: String): String {
|
|||
}
|
||||
}
|
||||
|
||||
fun sortUrls(urls: List<ExtractorLink>): List<ExtractorLink> {
|
||||
fun sortUrls(urls: Set<ExtractorLink>): List<ExtractorLink> {
|
||||
return urls.sortedBy { t -> -t.quality }
|
||||
}
|
||||
|
||||
fun sortSubs(urls: List<SubtitleFile>): List<SubtitleFile> {
|
||||
val encounteredTimes = HashMap<String, Int>()
|
||||
return urls.sortedBy { t -> t.lang }.map {
|
||||
val times = encounteredTimes[it.lang]?.plus(1) ?: 1
|
||||
encounteredTimes[it.lang] = times
|
||||
|
||||
SubtitleFile("${it.lang} ${if (times > 1) "($times)" else ""}", it.url)
|
||||
}
|
||||
fun sortSubs(subs : Set<SubtitleData>) : List<SubtitleData> {
|
||||
return subs.sortedBy { it.name }
|
||||
}
|
||||
|
||||
fun capitalizeString(str: String): String {
|
||||
|
@ -377,6 +372,11 @@ fun TvType.isMovieType(): Boolean {
|
|||
return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent
|
||||
}
|
||||
|
||||
// returns if the type has an anime opening
|
||||
fun TvType.isAnimeOp(): Boolean {
|
||||
return this == TvType.Anime || this == TvType.ONA
|
||||
}
|
||||
|
||||
data class SubtitleFile(val lang: String, val url: String)
|
||||
|
||||
class HomePageResponse(
|
||||
|
@ -463,7 +463,7 @@ interface LoadResponse {
|
|||
|
||||
fun LoadResponse?.isEpisodeBased(): Boolean {
|
||||
if (this == null) return false
|
||||
return (this is AnimeLoadResponse || this is TvSeriesLoadResponse) && (this.type == TvType.TvSeries || this.type == TvType.Anime)
|
||||
return (this is AnimeLoadResponse || this is TvSeriesLoadResponse) && this.type.isEpisodeBased()
|
||||
}
|
||||
|
||||
fun LoadResponse?.isAnimeBased(): Boolean {
|
||||
|
@ -471,6 +471,11 @@ fun LoadResponse?.isAnimeBased(): Boolean {
|
|||
return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse)
|
||||
}
|
||||
|
||||
fun TvType?.isEpisodeBased() : Boolean {
|
||||
if (this == null) return false
|
||||
return (this == TvType.TvSeries || this == TvType.Anime)
|
||||
}
|
||||
|
||||
data class AnimeEpisode(
|
||||
val url: String,
|
||||
var name: String? = null,
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
package com.lagradost.cloudstream3
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.KeyEvent.ACTION_DOWN
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import android.view.KeyEvent
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.findNavController
|
||||
|
@ -29,6 +19,12 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
|||
import com.lagradost.cloudstream3.APIHolder.apis
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||
import com.lagradost.cloudstream3.APIHolder.restrictedApis
|
||||
import com.lagradost.cloudstream3.CommonActivity.backEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
||||
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint
|
||||
import com.lagradost.cloudstream3.CommonActivity.updateLocale
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.network.Requests
|
||||
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
||||
|
@ -37,27 +33,22 @@ import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.OAuth2accoun
|
|||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.appString
|
||||
import com.lagradost.cloudstream3.ui.APIRepository
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||
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.hideKeyboard
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.showInputMethod
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
import java.util.*
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
|
@ -72,6 +63,7 @@ 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"
|
||||
|
||||
// Short name for requests client to make it nicer to use
|
||||
var app = Requests()
|
||||
|
||||
|
@ -91,7 +83,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
findNavController(R.id.nav_host_fragment).currentDestination?.let { updateNavBar(it) }
|
||||
}
|
||||
|
||||
private fun updateNavBar(destination : NavDestination) {
|
||||
private fun updateNavBar(destination: NavDestination) {
|
||||
this.hideKeyboard()
|
||||
|
||||
// Fucks up anime info layout since that has its own layout
|
||||
|
@ -106,7 +98,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
R.id.navigation_download_child
|
||||
).contains(destination.id)
|
||||
|
||||
val landscape = when(resources.configuration.orientation) {
|
||||
val landscape = when (resources.configuration.orientation) {
|
||||
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||
true
|
||||
}
|
||||
|
@ -181,268 +173,24 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
}
|
||||
|
||||
enum class FocusDirection {
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
private fun getNextFocus(view: View?, direction: FocusDirection, depth: Int = 0): Int? {
|
||||
if (view == null || depth >= 10) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nextId = when (direction) {
|
||||
FocusDirection.Left -> {
|
||||
view.nextFocusLeftId
|
||||
}
|
||||
FocusDirection.Up -> {
|
||||
view.nextFocusUpId
|
||||
}
|
||||
FocusDirection.Right -> {
|
||||
view.nextFocusRightId
|
||||
}
|
||||
FocusDirection.Down -> {
|
||||
view.nextFocusDownId
|
||||
}
|
||||
}
|
||||
|
||||
return if (nextId != -1) {
|
||||
val next = findViewById<View?>(nextId)
|
||||
//println("NAME: ${next.accessibilityClassName} | ${next?.isShown}" )
|
||||
|
||||
if (next?.isShown == false) {
|
||||
getNextFocus(next, direction, depth + 1)
|
||||
} else {
|
||||
if (depth == 0) {
|
||||
null
|
||||
} else {
|
||||
nextId
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
||||
event?.keyCode?.let { keyCode ->
|
||||
when (event.action) {
|
||||
ACTION_DOWN -> {
|
||||
if (currentFocus != null) {
|
||||
val next = when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(currentFocus, FocusDirection.Left)
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(currentFocus, FocusDirection.Right)
|
||||
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(currentFocus, FocusDirection.Up)
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(currentFocus, FocusDirection.Down)
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (next != null && next != -1) {
|
||||
val nextView = findViewById<View?>(next)
|
||||
if(nextView != null) {
|
||||
nextView.requestFocus()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
when (keyCode) {
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
println("DPAD PRESSED $currentFocus")
|
||||
if (currentFocus is SearchView || currentFocus is SearchView.SearchAutoComplete) {
|
||||
println("current PRESSED")
|
||||
showInputMethod(currentFocus?.findFocus())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//println("Keycode: $keyCode")
|
||||
//showToast(
|
||||
// this,
|
||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
||||
// Toast.LENGTH_LONG
|
||||
//)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyEventListener?.invoke(event) == true) {
|
||||
return true
|
||||
CommonActivity.dispatchKeyEvent(this, event)?.let {
|
||||
return it
|
||||
}
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
//println("Keycode: $keyCode")
|
||||
//showToast(
|
||||
// this,
|
||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
||||
// Toast.LENGTH_LONG
|
||||
//)
|
||||
|
||||
// Tested keycodes on remote:
|
||||
// KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
||||
// KeyEvent.KEYCODE_MEDIA_REWIND
|
||||
// KeyEvent.KEYCODE_MENU
|
||||
// KeyEvent.KEYCODE_MEDIA_NEXT
|
||||
// KeyEvent.KEYCODE_MEDIA_PREVIOUS
|
||||
// KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|
||||
|
||||
// 149 keycode_numpad 5
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {
|
||||
PlayerEventType.SeekForward
|
||||
}
|
||||
KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
|
||||
PlayerEventType.SeekBack
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1 -> {
|
||||
PlayerEventType.NextEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1 -> {
|
||||
PlayerEventType.PrevEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
||||
PlayerEventType.Pause
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> {
|
||||
PlayerEventType.Play
|
||||
}
|
||||
KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7 -> {
|
||||
PlayerEventType.Lock
|
||||
}
|
||||
KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> {
|
||||
PlayerEventType.ToggleHide
|
||||
}
|
||||
KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> {
|
||||
PlayerEventType.ToggleMute
|
||||
}
|
||||
KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9 -> {
|
||||
PlayerEventType.ShowMirrors
|
||||
}
|
||||
KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3 -> {
|
||||
PlayerEventType.ShowSpeed
|
||||
}
|
||||
KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0 -> {
|
||||
PlayerEventType.Resize
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation
|
||||
PlayerEventType.PlayPauseToggle
|
||||
}
|
||||
else -> null
|
||||
}?.let { playerEvent ->
|
||||
playerEventListener?.invoke(playerEvent)
|
||||
}
|
||||
|
||||
//when (keyCode) {
|
||||
// KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
// println("DPAD PRESSED")
|
||||
// }
|
||||
//}
|
||||
CommonActivity.onKeyDown(this, keyCode, event)
|
||||
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Activity?.getCastSession(): CastSession? {
|
||||
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
||||
}
|
||||
|
||||
var canEnterPipMode: Boolean = false
|
||||
var canShowPipMode: Boolean = false
|
||||
var isInPIPMode: Boolean = false
|
||||
|
||||
val backEvent = Event<Boolean>()
|
||||
val onColorSelectedEvent = Event<Pair<Int, Int>>()
|
||||
val onDialogDismissedEvent = Event<Int>()
|
||||
|
||||
var playerEventListener: ((PlayerEventType) -> Unit)? = null
|
||||
var keyEventListener: ((KeyEvent?) -> Boolean)? = null
|
||||
|
||||
|
||||
var currentToast: Toast? = null
|
||||
|
||||
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? = null) {
|
||||
if (act == null || message == 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.LENGTH_SHORT
|
||||
toast.view = layout
|
||||
toast.show()
|
||||
currentToast = toast
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun setLocale(context: Context?, languageCode: String?) {
|
||||
if (context == null || languageCode == null) return
|
||||
val locale = Locale(languageCode)
|
||||
val resources: Resources = context.resources
|
||||
val config = resources.configuration
|
||||
Locale.setDefault(locale)
|
||||
config.setLocale(locale)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
context.createConfigurationContext(config)
|
||||
resources.updateConfiguration(config, resources.displayMetrics)
|
||||
}
|
||||
|
||||
fun Context.updateLocale() {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val localeCode = settingsManager.getString(getString(R.string.locale_key), null)
|
||||
setLocale(this, localeCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun enterPIPMode() {
|
||||
if (!shouldShowPIPMode(canEnterPipMode) || !canShowPipMode) return
|
||||
try {
|
||||
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()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUserLeaveHint() {
|
||||
super.onUserLeaveHint()
|
||||
if (canEnterPipMode && canShowPipMode) {
|
||||
enterPIPMode()
|
||||
}
|
||||
onUserLeaveHint(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@ -456,9 +204,15 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
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
|
||||
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
|
||||
data.getLongExtra(
|
||||
VLC_EXTRA_DURATION_OUT,
|
||||
-1
|
||||
) //Last position in media when player exited
|
||||
val id = getKey<Int>(VLC_LAST_ID_KEY)
|
||||
println("SET KEY $id at $pos / $dur")
|
||||
if (dur > 0 && pos > 0) {
|
||||
|
@ -486,6 +240,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
private fun handleAppIntent(intent: Intent?) {
|
||||
if (intent == null) return
|
||||
val str = intent.dataString
|
||||
loadCache()
|
||||
if (str != null) {
|
||||
if (str.contains(appString)) {
|
||||
for (api in OAuth2Apis) {
|
||||
|
@ -513,37 +268,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
for (api in OAuth2accountApis) {
|
||||
api.init()
|
||||
}
|
||||
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
val currentTheme = when (settingsManager.getString(getString(R.string.app_theme_key), "AmoledLight")) {
|
||||
"Black" -> R.style.AppTheme
|
||||
"Light" -> R.style.LightMode
|
||||
"Amoled" -> R.style.AmoledMode
|
||||
"AmoledLight" -> R.style.AmoledModeLight
|
||||
else -> R.style.AppTheme
|
||||
}
|
||||
|
||||
val currentOverlayTheme = when (settingsManager.getString(getString(R.string.primary_color_key), "Normal")) {
|
||||
"Normal" -> R.style.OverlayPrimaryColorNormal
|
||||
"Blue" -> R.style.OverlayPrimaryColorBlue
|
||||
"Purple" -> R.style.OverlayPrimaryColorPurple
|
||||
"Green" -> R.style.OverlayPrimaryColorGreen
|
||||
"GreenApple" -> R.style.OverlayPrimaryColorGreenApple
|
||||
"Red" -> R.style.OverlayPrimaryColorRed
|
||||
"Banana" -> R.style.OverlayPrimaryColorBanana
|
||||
"Party" -> R.style.OverlayPrimaryColorParty
|
||||
else -> R.style.OverlayPrimaryColorNormal
|
||||
}
|
||||
|
||||
theme.applyStyle(currentTheme, true)
|
||||
theme.applyStyle(currentOverlayTheme, true)
|
||||
|
||||
theme.applyStyle(
|
||||
R.style.LoadedStyle,
|
||||
true
|
||||
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
|
||||
|
||||
loadThemes(this)
|
||||
updateLocale()
|
||||
app.initClient(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -565,12 +290,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
|
||||
// val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
||||
|
||||
//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
|
||||
|
||||
CommonActivity.init(this)
|
||||
|
||||
val navController = findNavController(R.id.nav_host_fragment)
|
||||
|
||||
|
@ -588,6 +309,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
updateNavBar(destination)
|
||||
}
|
||||
loadCache()
|
||||
|
||||
/*nav_view.setOnNavigationItemSelectedListener { item ->
|
||||
when (item.itemId) {
|
||||
|
@ -721,6 +443,14 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
APIRepository.dubStatusActive = getApiDubstatusSettings()
|
||||
|
||||
try {
|
||||
// this ensures that no unnecessary space is taken
|
||||
loadCache()
|
||||
File(filesDir, "exoplayer").deleteRecursively() // old cache
|
||||
File(cacheDir, "exoplayer").deleteOnExit() // current cache
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
|
||||
/*
|
||||
val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import java.util.*
|
||||
|
||||
|
@ -107,8 +107,11 @@ class GogoanimeProvider : MainAPI() {
|
|||
this.name,
|
||||
TvType.Anime,
|
||||
it.selectFirst("img").attr("src"),
|
||||
it.selectFirst(".released")?.text()?.split(":")?.getOrNull(1)?.trim()?.toIntOrNull(),
|
||||
if (it.selectFirst(".name").text().contains("Dub")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
|
||||
it.selectFirst(".released")?.text()?.split(":")?.getOrNull(1)?.trim()
|
||||
?.toIntOrNull(),
|
||||
if (it.selectFirst(".name").text()
|
||||
.contains("Dub")
|
||||
) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
|
||||
DubStatus.Subbed
|
||||
),
|
||||
)
|
||||
|
@ -191,22 +194,20 @@ class GogoanimeProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun extractVideos(uri: String): List<ExtractorLink> {
|
||||
val html = app.get(uri).text
|
||||
val doc = Jsoup.parse(html)
|
||||
private fun extractVideos(uri: String, callback: (ExtractorLink) -> Unit) {
|
||||
val doc = app.get(uri).document
|
||||
|
||||
val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe").attr("src")) ?: return
|
||||
|
||||
val iframe = "https:" + doc.selectFirst("div.play-video > iframe").attr("src")
|
||||
val link = iframe.replace("streaming.php", "download")
|
||||
|
||||
val page = app.get(link, headers = mapOf("Referer" to iframe))
|
||||
val pageDoc = Jsoup.parse(page.text)
|
||||
|
||||
return pageDoc.select(".dowload > a").pmap {
|
||||
page.document.select(".dowload > a").pmap {
|
||||
if (it.hasAttr("download")) {
|
||||
val qual = if (it.text()
|
||||
.contains("HDP")
|
||||
) "1080" else qualityRegex.find(it.text())?.destructured?.component1().toString()
|
||||
listOf(
|
||||
callback(
|
||||
ExtractorLink(
|
||||
"Gogoanime",
|
||||
if (qual == "null") "Gogoanime" else "Gogoanime - " + qual + "p",
|
||||
|
@ -218,16 +219,18 @@ class GogoanimeProvider : MainAPI() {
|
|||
)
|
||||
} else {
|
||||
val url = it.attr("href")
|
||||
val extractorLinks = ArrayList<ExtractorLink>()
|
||||
for (api in extractorApis) {
|
||||
if (url.startsWith(api.mainUrl)) {
|
||||
extractorLinks.addAll(api.getSafeUrl(url) ?: listOf())
|
||||
break
|
||||
}
|
||||
}
|
||||
extractorLinks
|
||||
loadExtractor(url, null, callback)
|
||||
}
|
||||
}
|
||||
|
||||
val streamingResponse = app.get(iframe, headers = mapOf("Referer" to iframe))
|
||||
streamingResponse.document.select(".list-server-items > .linkserver")
|
||||
?.forEach { element ->
|
||||
val status = element.attr("data-status") ?: return@forEach
|
||||
if (status != "1") return@forEach
|
||||
val data = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(data, streamingResponse.url, callback)
|
||||
}
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
override fun loadLinks(
|
||||
|
@ -236,9 +239,7 @@ class GogoanimeProvider : MainAPI() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
for (source in extractVideos(data)) {
|
||||
callback.invoke(source)
|
||||
}
|
||||
extractVideos(data, callback)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ import com.google.android.gms.cast.framework.CastSession
|
|||
import com.google.android.gms.cast.framework.media.RemoteMediaClient
|
||||
import com.google.android.gms.cast.framework.media.uicontroller.UIController
|
||||
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.sortSubs
|
||||
import com.lagradost.cloudstream3.sortUrls
|
||||
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks
|
||||
import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo
|
||||
|
@ -86,10 +88,11 @@ data class MetadataHolder(
|
|||
val currentEpisodeIndex: Int,
|
||||
val episodes: List<ResultEpisode>,
|
||||
val currentLinks: List<ExtractorLink>,
|
||||
val currentSubtitles: List<SubtitleFile>
|
||||
val currentSubtitles: List<SubtitleData>
|
||||
)
|
||||
|
||||
class SelectSourceController(val view: ImageView, val activity: ControllerActivity) : UIController() {
|
||||
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()
|
||||
|
||||
|
@ -106,17 +109,22 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
|||
remoteMediaClient?.mediaInfo?.mediaTracks?.filter { it.type == MediaTrack.TYPE_TEXT }
|
||||
?: ArrayList()
|
||||
|
||||
val bottomSheetDialogBuilder = AlertDialog.Builder(view.context, R.style.AlertDialogCustomBlack)
|
||||
val bottomSheetDialogBuilder =
|
||||
AlertDialog.Builder(view.context, R.style.AlertDialogCustomBlack)
|
||||
bottomSheetDialogBuilder.setView(R.layout.sort_bottom_sheet)
|
||||
val bottomSheetDialog = bottomSheetDialogBuilder.create()
|
||||
bottomSheetDialog.show()
|
||||
// bottomSheetDialog.setContentView(R.layout.sort_bottom_sheet)
|
||||
val providerList = bottomSheetDialog.findViewById<ListView>(R.id.sort_providers)!!
|
||||
val subtitleList = bottomSheetDialog.findViewById<ListView>(R.id.sort_subtitles)!!
|
||||
val providerList =
|
||||
bottomSheetDialog.findViewById<ListView>(R.id.sort_providers)!!
|
||||
val subtitleList =
|
||||
bottomSheetDialog.findViewById<ListView>(R.id.sort_subtitles)!!
|
||||
if (subTracks.isEmpty()) {
|
||||
bottomSheetDialog.findViewById<LinearLayout>(R.id.sort_subtitles_holder)?.visibility = GONE
|
||||
bottomSheetDialog.findViewById<LinearLayout>(R.id.sort_subtitles_holder)?.visibility =
|
||||
GONE
|
||||
} else {
|
||||
val arrayAdapter = ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
|
||||
arrayAdapter.add(view.context.getString(R.string.no_subtitles))
|
||||
arrayAdapter.addAll(subTracks.mapNotNull { it.name })
|
||||
|
||||
|
@ -168,7 +176,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
|||
val sortingMethods = items.map { it.name }.toTypedArray()
|
||||
val sotringIndex = items.indexOfFirst { it.url == contentUrl }
|
||||
|
||||
val arrayAdapter = ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
|
||||
arrayAdapter.addAll(sortingMethods.toMutableList())
|
||||
|
||||
providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
|
@ -196,7 +205,9 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
|||
try { // THIS IS VERY IMPORTANT BECAUSE WE NEVER WANT TO AUTOLOAD THE NEXT EPISODE
|
||||
val currentIdIndex = remoteMediaClient?.getItemIndex()
|
||||
|
||||
val nextId = remoteMediaClient?.mediaQueue?.itemIds?.get(currentIdIndex?.plus(1) ?: 0)
|
||||
val nextId = remoteMediaClient?.mediaQueue?.itemIds?.get(
|
||||
currentIdIndex?.plus(1) ?: 0
|
||||
)
|
||||
if (currentIdIndex == null && nextId != null) {
|
||||
awaitLinks(
|
||||
remoteMediaClient?.queueInsertAndPlayItem(
|
||||
|
@ -256,26 +267,29 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
|||
thread {
|
||||
val index = meta.currentEpisodeIndex + 1
|
||||
val epData = meta.episodes[index]
|
||||
val links = ArrayList<ExtractorLink>()
|
||||
val subs = ArrayList<SubtitleFile>()
|
||||
val currentLinks = mutableSetOf<ExtractorLink>()
|
||||
val currentSubs = mutableSetOf<SubtitleData>()
|
||||
|
||||
val isSuccessful =
|
||||
APIRepository(getApiFromName(meta.apiName)).loadLinks(epData.data, true, { subtitleFile ->
|
||||
if (!subs.any { it.url == subtitleFile.url }) {
|
||||
subs.add(subtitleFile)
|
||||
}
|
||||
}) { link ->
|
||||
if (!links.any { it.url == link.url }) {
|
||||
links.add(link)
|
||||
}
|
||||
}
|
||||
val generator = RepoLinkGenerator(listOf(epData))
|
||||
|
||||
if (isSuccessful) {
|
||||
val sorted = sortUrls(links)
|
||||
if (sorted.isNotEmpty()) {
|
||||
val isSuccessful = normalSafeApiCall {
|
||||
generator.generateLinks(false, true,
|
||||
{
|
||||
it.first?.let { link ->
|
||||
currentLinks.add(link)
|
||||
}
|
||||
}, {
|
||||
currentSubs.add(it)
|
||||
})
|
||||
}
|
||||
|
||||
val sortedLinks = sortUrls(currentLinks)
|
||||
val sortedSubs = sortSubs(currentSubs)
|
||||
if (isSuccessful == true) {
|
||||
if (currentLinks.isNotEmpty()) {
|
||||
val jsonCopy = meta.copy(
|
||||
currentLinks = sorted,
|
||||
currentSubtitles = subs,
|
||||
currentLinks = sortedLinks,
|
||||
currentSubtitles = sortedSubs,
|
||||
currentEpisodeIndex = index
|
||||
)
|
||||
|
||||
|
@ -287,7 +301,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
|||
jsonCopy,
|
||||
0,
|
||||
done,
|
||||
subs
|
||||
sortedSubs
|
||||
)
|
||||
|
||||
/*fun loadIndex(index: Int) {
|
||||
|
@ -367,9 +381,21 @@ class ControllerActivity : ExpandedControllerActivity() {
|
|||
val skipBackButton: ImageView = getButtonImageViewAt(1)
|
||||
val skipForwardButton: ImageView = getButtonImageViewAt(2)
|
||||
val skipOpButton: ImageView = getButtonImageViewAt(3)
|
||||
uiMediaController.bindViewToUIController(sourcesButton, SelectSourceController(sourcesButton, this))
|
||||
uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false))
|
||||
uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true))
|
||||
uiMediaController.bindViewToUIController(skipOpButton, SkipNextEpisodeController(skipOpButton))
|
||||
uiMediaController.bindViewToUIController(
|
||||
sourcesButton,
|
||||
SelectSourceController(sourcesButton, this)
|
||||
)
|
||||
uiMediaController.bindViewToUIController(
|
||||
skipBackButton,
|
||||
SkipTimeController(skipBackButton, false)
|
||||
)
|
||||
uiMediaController.bindViewToUIController(
|
||||
skipForwardButton,
|
||||
SkipTimeController(skipForwardButton, true)
|
||||
)
|
||||
uiMediaController.bindViewToUIController(
|
||||
skipOpButton,
|
||||
SkipNextEpisodeController(skipOpButton)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -4,14 +4,15 @@ import android.app.Activity
|
|||
import android.content.DialogInterface
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||
import com.lagradost.cloudstream3.ui.player.UriData
|
||||
import com.lagradost.cloudstream3.ui.player.DownloadFileGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
|
@ -49,7 +50,7 @@ object DownloadButtonSetup {
|
|||
.setPositiveButton(R.string.delete, dialogClickListener)
|
||||
.setNegativeButton(R.string.cancel, dialogClickListener)
|
||||
.show()
|
||||
} catch (e : Exception) {
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
// ye you somehow fucked up formatting did you?
|
||||
}
|
||||
|
@ -81,40 +82,71 @@ object DownloadButtonSetup {
|
|||
DOWNLOAD_ACTION_LONG_CLICK -> {
|
||||
activity?.let { act ->
|
||||
val length =
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(act, click.data.id)?.fileLength
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
act,
|
||||
click.data.id
|
||||
)?.fileLength
|
||||
?: 0
|
||||
if (length > 0) {
|
||||
MainActivity.showToast(act, R.string.delete, Toast.LENGTH_LONG)
|
||||
showToast(act, R.string.delete, Toast.LENGTH_LONG)
|
||||
} else {
|
||||
MainActivity.showToast(act, R.string.download, Toast.LENGTH_LONG)
|
||||
showToast(act, R.string.download, Toast.LENGTH_LONG)
|
||||
}
|
||||
}
|
||||
}
|
||||
DOWNLOAD_ACTION_PLAY_FILE -> {
|
||||
activity?.let { act ->
|
||||
val info =
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(act, click.data.id)
|
||||
?: return
|
||||
val keyInfo = act.getKey<VideoDownloadManager.DownloadedFileInfo>(
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
act,
|
||||
click.data.id
|
||||
) ?: return
|
||||
val keyInfo = getKey<VideoDownloadManager.DownloadedFileInfo>(
|
||||
VideoDownloadManager.KEY_DOWNLOAD_INFO,
|
||||
click.data.id.toString()
|
||||
) ?: return
|
||||
val parent = getKey<VideoDownloadHelper.DownloadHeaderCached>(
|
||||
DOWNLOAD_HEADER_CACHE,
|
||||
click.data.parentId.toString()
|
||||
) ?: return
|
||||
|
||||
act.navigate(
|
||||
R.id.global_to_navigation_player, PlayerFragment.newInstance(
|
||||
UriData(
|
||||
info.path.toString(),
|
||||
keyInfo.basePath,
|
||||
keyInfo.relativePath,
|
||||
keyInfo.displayName,
|
||||
click.data.parentId,
|
||||
click.data.id,
|
||||
headerName ?: "null",
|
||||
if (click.data.episode <= 0) null else click.data.episode,
|
||||
click.data.season
|
||||
),
|
||||
getViewPos(click.data.id)?.position ?: 0
|
||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||
DownloadFileGenerator(
|
||||
listOf(
|
||||
ExtractorUri(
|
||||
uri = info.path,
|
||||
|
||||
id = click.data.id,
|
||||
parentId = click.data.parentId,
|
||||
name = act.getString(R.string.downloaded_file), //click.data.name ?: keyInfo.displayName
|
||||
season = click.data.season,
|
||||
episode = click.data.episode,
|
||||
headerName = parent.name,
|
||||
tvType = parent.type,
|
||||
|
||||
basePath = keyInfo.basePath,
|
||||
displayName = keyInfo.displayName,
|
||||
relativePath = keyInfo.relativePath,
|
||||
)
|
||||
),
|
||||
0
|
||||
)
|
||||
)
|
||||
//R.id.global_to_navigation_player, PlayerFragment.newInstance(
|
||||
// UriData(
|
||||
// info.path.toString(),
|
||||
// keyInfo.basePath,
|
||||
// keyInfo.relativePath,
|
||||
// keyInfo.displayName,
|
||||
// click.data.parentId,
|
||||
// click.data.id,
|
||||
// headerName ?: "null",
|
||||
// if (click.data.episode <= 0) null else click.data.episode,
|
||||
// click.data.season
|
||||
// ),
|
||||
// getViewPos(click.data.id)?.position ?: 0
|
||||
//)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,8 +177,7 @@ class HomeViewModel : ViewModel() {
|
|||
logError(e)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
_page.postValue(data)
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,346 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.drawable.AnimatedImageDrawable
|
||||
import android.graphics.drawable.AnimatedVectorDrawable
|
||||
import android.media.metrics.PlaybackErrorEvent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.PlaybackException
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||
import com.google.android.exoplayer2.ui.SubtitleView
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
|
||||
import com.lagradost.cloudstream3.CommonActivity.isInPIPMode
|
||||
import com.lagradost.cloudstream3.CommonActivity.keyEventListener
|
||||
import com.lagradost.cloudstream3.CommonActivity.playerEventListener
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.requestLocalAudioFocus
|
||||
import com.lagradost.cloudstream3.utils.UIHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||
import kotlinx.android.synthetic.main.fragment_player.*
|
||||
import kotlinx.android.synthetic.main.player_custom_layout.*
|
||||
|
||||
enum class PlayerResize(@StringRes val nameRes: Int) {
|
||||
Fit(R.string.resize_fit),
|
||||
Fill(R.string.resize_fill),
|
||||
Zoom(R.string.resize_zoom),
|
||||
}
|
||||
|
||||
// when the player should switch skip op to next episode
|
||||
const val SKIP_OP_VIDEO_PERCENTAGE = 50
|
||||
|
||||
// when the player should preload the next episode for faster loading
|
||||
const val PRELOAD_NEXT_EPISODE_PERCENTAGE = 80
|
||||
|
||||
// when the player should mark the episode as watched and resume watching the next
|
||||
const val NEXT_WATCH_EPISODE_PERCENTAGE = 95
|
||||
|
||||
abstract class AbstractPlayerFragment(
|
||||
@LayoutRes val layout: Int,
|
||||
val player: IPlayer = CS3IPlayer()
|
||||
) : Fragment() {
|
||||
var resizeMode: Int = 0
|
||||
var subStyle: SaveCaptionStyle? = null
|
||||
var subView: SubtitleView? = null
|
||||
var isBuffering = true
|
||||
|
||||
open fun nextEpisode() {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
open fun prevEpisode() {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
open fun playerPositionChanged(posDur: Pair<Long, Long>) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
open fun playerDimensionsLoaded(widthHeight : Pair<Int, Int>) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
private fun updateIsPlaying(playing: Pair<CSPlayerLoading, CSPlayerLoading>) {
|
||||
val (wasPlaying, isPlaying) = playing
|
||||
val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying
|
||||
|
||||
isBuffering = CSPlayerLoading.IsBuffering == isPlaying
|
||||
if (isBuffering) {
|
||||
player_pause_play_holder_holder?.isVisible = false
|
||||
player_buffering?.isVisible = true
|
||||
} else {
|
||||
player_pause_play_holder_holder?.isVisible = true
|
||||
player_buffering?.isVisible = false
|
||||
|
||||
if (wasPlaying != isPlaying) {
|
||||
player_pause_play?.setImageResource(if (isPlayingRightNow) R.drawable.play_to_pause else R.drawable.pause_to_play)
|
||||
val drawable = player_pause_play?.drawable
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
if (drawable is AnimatedImageDrawable) {
|
||||
drawable.start()
|
||||
}
|
||||
}
|
||||
if (drawable is AnimatedVectorDrawable) {
|
||||
drawable.start()
|
||||
}
|
||||
} else {
|
||||
player_pause_play?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||
}
|
||||
}
|
||||
|
||||
canEnterPipMode = isPlayingRightNow
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
activity?.let { act ->
|
||||
PlayerPipHelper.updatePIPModeActions(act, isPlayingRightNow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var pipReceiver: BroadcastReceiver? = null
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
try {
|
||||
isInPIPMode = isInPictureInPictureMode
|
||||
if (isInPictureInPictureMode) {
|
||||
// Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
|
||||
player_holder.alpha = 0f
|
||||
pipReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(
|
||||
context: Context,
|
||||
intent: Intent,
|
||||
) {
|
||||
if (ACTION_MEDIA_CONTROL != intent.action) {
|
||||
return
|
||||
}
|
||||
player.handleEvent(
|
||||
CSPlayerEvent.values()[intent.getIntExtra(
|
||||
EXTRA_CONTROL_TYPE,
|
||||
0
|
||||
)]
|
||||
)
|
||||
}
|
||||
}
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(
|
||||
ACTION_MEDIA_CONTROL
|
||||
)
|
||||
activity?.registerReceiver(pipReceiver, filter)
|
||||
val isPlaying = player.getIsPlaying()
|
||||
val isPlayingValue =
|
||||
if (isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused
|
||||
updateIsPlaying(Pair(isPlayingValue, isPlayingValue))
|
||||
} else {
|
||||
// Restore the full-screen UI.
|
||||
player_holder.alpha = 1f
|
||||
pipReceiver?.let {
|
||||
activity?.unregisterReceiver(it)
|
||||
}
|
||||
activity?.hideSystemUI()
|
||||
this.view?.let { UIHelper.hideKeyboard(it) }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
open fun nextMirror() {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
private fun playerError(exception: Exception) {
|
||||
when (exception) {
|
||||
is PlaybackException -> {
|
||||
val msg = exception.message ?: ""
|
||||
val errorName = exception.errorCodeName
|
||||
when (val code = exception.errorCode) {
|
||||
PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND, PlaybackException.ERROR_CODE_IO_NO_PERMISSION, PlaybackException.ERROR_CODE_IO_UNSPECIFIED -> {
|
||||
showToast(
|
||||
activity,
|
||||
"${getString(R.string.source_error)}\n$errorName ($code)\n$msg",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
nextMirror()
|
||||
}
|
||||
PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> {
|
||||
showToast(
|
||||
activity,
|
||||
"${getString(R.string.remote_error)}\n$errorName ($code)\n$msg",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
nextMirror()
|
||||
}
|
||||
PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> {
|
||||
showToast(
|
||||
activity,
|
||||
"${getString(R.string.render_error)}\n$errorName ($code)\n$msg",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
nextMirror()
|
||||
}
|
||||
else -> {
|
||||
showToast(
|
||||
activity,
|
||||
"${getString(R.string.unexpected_error)}\n$errorName ($code)\n$msg",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
showToast(activity, exception.message, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestAudioFocus() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
activity?.requestLocalAudioFocus(AppUtils.getFocusRequest())
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSubStyleChanged(style: SaveCaptionStyle) {
|
||||
if (player is CS3IPlayer) {
|
||||
player.updateSubtitleStyle(style)
|
||||
}
|
||||
}
|
||||
|
||||
private fun playerUpdated(player: Any?) {
|
||||
if (player is ExoPlayer) {
|
||||
player_view?.player = player
|
||||
player_view?.performClick()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
|
||||
resize(resizeMode, false)
|
||||
|
||||
player.initCallbacks(
|
||||
playerUpdated = ::playerUpdated,
|
||||
updateIsPlaying = ::updateIsPlaying,
|
||||
playerError = ::playerError,
|
||||
requestAutoFocus = ::requestAudioFocus,
|
||||
nextEpisode = ::nextEpisode,
|
||||
prevEpisode = ::prevEpisode,
|
||||
playerPositionChanged = ::playerPositionChanged,
|
||||
playerDimensionsLoaded = ::playerDimensionsLoaded,
|
||||
requestedListeningPercentages = listOf(
|
||||
SKIP_OP_VIDEO_PERCENTAGE,
|
||||
PRELOAD_NEXT_EPISODE_PERCENTAGE,
|
||||
NEXT_WATCH_EPISODE_PERCENTAGE,
|
||||
)
|
||||
)
|
||||
|
||||
if (player is CS3IPlayer) {
|
||||
subView = player_view?.findViewById(R.id.exo_subtitles)
|
||||
subStyle = SubtitlesFragment.getCurrentSavedStyle()
|
||||
player.initSubtitles(subView, subtitle_holder, subStyle)
|
||||
SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged
|
||||
}
|
||||
|
||||
/*context?.let { ctx ->
|
||||
player.loadPlayer(
|
||||
ctx,
|
||||
false,
|
||||
ExtractorLink(
|
||||
"idk",
|
||||
"bunny",
|
||||
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
|
||||
"",
|
||||
Qualities.P720.value,
|
||||
false
|
||||
),
|
||||
)
|
||||
}*/
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
playerEventListener = null
|
||||
keyEventListener = null
|
||||
SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged
|
||||
|
||||
// simply resets brightness and notch settings that might have been overridden
|
||||
val lp = activity?.window?.attributes
|
||||
lp?.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
lp?.layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|
||||
}
|
||||
activity?.window?.attributes = lp
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun nextResize() {
|
||||
resizeMode = (resizeMode + 1) % PlayerResize.values().size
|
||||
resize(resizeMode, true)
|
||||
}
|
||||
|
||||
fun resize(resize: Int, showToast: Boolean) {
|
||||
resize(PlayerResize.values()[resize], showToast)
|
||||
}
|
||||
|
||||
fun resize(resize: PlayerResize, showToast: Boolean) {
|
||||
setKey(RESIZE_MODE_KEY, resize.ordinal)
|
||||
val type = when (resize) {
|
||||
PlayerResize.Fill -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
PlayerResize.Fit -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
PlayerResize.Zoom -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
}
|
||||
player_view?.resizeMode = type
|
||||
|
||||
exo_play?.setOnClickListener {
|
||||
player.handleEvent(CSPlayerEvent.Play)
|
||||
}
|
||||
|
||||
exo_pause?.setOnClickListener {
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
}
|
||||
|
||||
if (showToast)
|
||||
showToast(activity, resize.nameRes, Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
player.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
context?.let { ctx ->
|
||||
player.onResume(ctx)
|
||||
}
|
||||
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(layout, container, false)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,668 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.FrameLayout
|
||||
import com.google.android.exoplayer2.*
|
||||
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
|
||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource
|
||||
import com.google.android.exoplayer2.text.Cue
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector
|
||||
import com.google.android.exoplayer2.ui.SubtitleView
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
|
||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache
|
||||
import com.google.android.exoplayer2.util.MimeTypes
|
||||
import com.lagradost.cloudstream3.USER_AGENT
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import java.io.File
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLSession
|
||||
|
||||
const val TAG = "CS3ExoPlayer"
|
||||
|
||||
class CS3IPlayer : IPlayer {
|
||||
private var isPlaying = false
|
||||
private var exoPlayer: ExoPlayer? = null
|
||||
|
||||
/** Cache */
|
||||
private val cacheSize = 300L * 1024L * 1024L // 300 mb TODO MAKE SETTING
|
||||
private val seekActionTime = 30000L
|
||||
|
||||
private var ignoreSSL: Boolean = true
|
||||
private var simpleCache: SimpleCache? = null
|
||||
private var playBackSpeed: Float = 1.0f
|
||||
|
||||
private var lastMuteVolume: Float = 1.0f
|
||||
|
||||
private var currentLink: ExtractorLink? = null
|
||||
private var currentDownloadedFile: ExtractorUri? = null
|
||||
private var hasUsedFirstRender = false
|
||||
|
||||
private var currentWindow: Int = 0
|
||||
private var playbackPosition: Long = 0
|
||||
|
||||
private val subtitleHelper = PlayerSubtitleHelper()
|
||||
|
||||
override fun getDuration(): Long? = exoPlayer?.duration
|
||||
override fun getPosition(): Long? = exoPlayer?.currentPosition
|
||||
override fun getIsPlaying(): Boolean = isPlaying
|
||||
override fun getPlaybackSpeed(): Float = playBackSpeed
|
||||
|
||||
/**
|
||||
* Tracks reported to be used by exoplayer, since sometimes it has a mind of it's own when selecting subs.
|
||||
* String = lowercase language as set by .setLanguage("_$langId")
|
||||
* Boolean = if it's active
|
||||
* */
|
||||
private var exoPlayerSelectedTracks = listOf<Pair<String, Boolean>>()
|
||||
|
||||
/** isPlaying */
|
||||
private var updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)? = null
|
||||
private var requestAutoFocus: (() -> Unit)? = null
|
||||
private var playerError: ((Exception) -> Unit)? = null
|
||||
|
||||
/** width x height */
|
||||
private var playerDimensionsLoaded: ((Pair<Int, Int>) -> Unit)? = null
|
||||
|
||||
/** used for playerPositionChanged */
|
||||
private var requestedListeningPercentages: List<Int>? = null
|
||||
|
||||
/** Fired when seeking the player or on requestedListeningPercentages,
|
||||
* used to make things appear on que
|
||||
* position, duration */
|
||||
private var playerPositionChanged: ((Pair<Long, Long>) -> Unit)? = null
|
||||
|
||||
private var nextEpisode: (() -> Unit)? = null
|
||||
private var prevEpisode: (() -> Unit)? = null
|
||||
|
||||
private var playerUpdated: ((Any?) -> Unit)? = null
|
||||
|
||||
override fun initCallbacks(
|
||||
playerUpdated: (Any?) -> Unit,
|
||||
updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)?,
|
||||
requestAutoFocus: (() -> Unit)?,
|
||||
playerError: ((Exception) -> Unit)?,
|
||||
playerDimensionsLoaded: ((Pair<Int, Int>) -> Unit)?,
|
||||
requestedListeningPercentages: List<Int>?,
|
||||
playerPositionChanged: ((Pair<Long, Long>) -> Unit)?,
|
||||
nextEpisode: (() -> Unit)?,
|
||||
prevEpisode: (() -> Unit)?
|
||||
) {
|
||||
this.playerUpdated = playerUpdated
|
||||
this.updateIsPlaying = updateIsPlaying
|
||||
this.requestAutoFocus = requestAutoFocus
|
||||
this.playerError = playerError
|
||||
this.playerDimensionsLoaded = playerDimensionsLoaded
|
||||
this.requestedListeningPercentages = requestedListeningPercentages
|
||||
this.playerPositionChanged = playerPositionChanged
|
||||
this.nextEpisode = nextEpisode
|
||||
this.prevEpisode = prevEpisode
|
||||
}
|
||||
|
||||
fun initSubtitles(subView: SubtitleView?, subHolder: FrameLayout?, style: SaveCaptionStyle?) {
|
||||
subtitleHelper.initSubtitles(subView, subHolder, style)
|
||||
}
|
||||
|
||||
override fun loadPlayer(
|
||||
context: Context,
|
||||
sameEpisode: Boolean,
|
||||
link: ExtractorLink?,
|
||||
data: ExtractorUri?,
|
||||
startPosition: Long?,
|
||||
subtitles: Set<SubtitleData>
|
||||
) {
|
||||
Log.i(TAG, "loadPlayer")
|
||||
if (sameEpisode) {
|
||||
saveData()
|
||||
} else {
|
||||
currentSubtitles = null
|
||||
playbackPosition = 0
|
||||
}
|
||||
|
||||
startPosition?.let {
|
||||
playbackPosition = it
|
||||
}
|
||||
|
||||
// we want autoplay because of TV and UX
|
||||
isPlaying = true
|
||||
|
||||
// release the current exoplayer and cache
|
||||
releasePlayer()
|
||||
if (link != null) {
|
||||
loadOnlinePlayer(context, link)
|
||||
} else if (data != null) {
|
||||
loadOfflinePlayer(context, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setActiveSubtitles(subtitles: Set<SubtitleData>) {
|
||||
Log.i(TAG, "setActiveSubtitles ${subtitles.size}")
|
||||
subtitleHelper.setAllSubtitles(subtitles)
|
||||
}
|
||||
|
||||
var currentSubtitles : SubtitleData? = null
|
||||
override fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean {
|
||||
Log.i(TAG,"setPreferredSubtitles init $subtitle")
|
||||
currentSubtitles = subtitle
|
||||
return (exoPlayer?.trackSelector as? DefaultTrackSelector?)?.let { trackSelector ->
|
||||
val name = subtitle?.name
|
||||
if (name.isNullOrBlank()) {
|
||||
trackSelector.setParameters(
|
||||
trackSelector.buildUponParameters()
|
||||
.setPreferredTextLanguage(null)
|
||||
)
|
||||
} else {
|
||||
when (subtitleHelper.subtitleStatus(subtitle)) {
|
||||
SubtitleStatus.REQUIRES_RELOAD -> {
|
||||
Log.i(TAG,"setPreferredSubtitles REQUIRES_RELOAD")
|
||||
return@let true
|
||||
// reloadPlayer(context)
|
||||
}
|
||||
SubtitleStatus.IS_ACTIVE -> {
|
||||
Log.i(TAG,"setPreferredSubtitles IS_ACTIVE")
|
||||
|
||||
trackSelector.setParameters(
|
||||
trackSelector.buildUponParameters()
|
||||
.setPreferredTextLanguage("_$name")
|
||||
)
|
||||
}
|
||||
SubtitleStatus.NOT_FOUND -> {
|
||||
// not found
|
||||
Log.i(TAG,"setPreferredSubtitles NOT_FOUND")
|
||||
return@let true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
} ?: false
|
||||
}
|
||||
|
||||
override fun getCurrentPreferredSubtitle(): SubtitleData? {
|
||||
return subtitleHelper.getAllSubtitles().firstOrNull { sub ->
|
||||
exoPlayerSelectedTracks.any {
|
||||
// The replace is needed as exoplayer translates _ to -
|
||||
// Also we prefix the languages with _
|
||||
it.second && it.first.replace("-", "") .equals(
|
||||
sub.name.replace("-", ""),
|
||||
ignoreCase = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateSubtitleStyle(style: SaveCaptionStyle) {
|
||||
subtitleHelper.setSubStyle(style)
|
||||
}
|
||||
|
||||
private fun saveData() {
|
||||
Log.i(TAG, "saveData")
|
||||
updatedTime()
|
||||
|
||||
exoPlayer?.let { exo ->
|
||||
playbackPosition = exo.currentPosition
|
||||
currentWindow = exo.currentWindowIndex
|
||||
isPlaying = exo.isPlaying
|
||||
}
|
||||
}
|
||||
|
||||
private fun releasePlayer() {
|
||||
Log.i(TAG, "releasePlayer")
|
||||
|
||||
updatedTime()
|
||||
|
||||
exoPlayer?.release()
|
||||
simpleCache?.release()
|
||||
|
||||
exoPlayer = null
|
||||
simpleCache = null
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
Log.i(TAG, "onStop")
|
||||
|
||||
saveData()
|
||||
exoPlayer?.pause()
|
||||
releasePlayer()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
Log.i(TAG, "onPause")
|
||||
saveData()
|
||||
exoPlayer?.pause()
|
||||
releasePlayer()
|
||||
}
|
||||
|
||||
override fun onResume(context: Context) {
|
||||
if (exoPlayer == null)
|
||||
reloadPlayer(context)
|
||||
}
|
||||
|
||||
override fun release() {
|
||||
releasePlayer()
|
||||
}
|
||||
|
||||
override fun setPlaybackSpeed(speed: Float) {
|
||||
exoPlayer?.setPlaybackSpeed(speed)
|
||||
playBackSpeed = speed
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun createOnlineSource(link: ExtractorLink): DataSource.Factory {
|
||||
return DefaultHttpDataSource.Factory().apply {
|
||||
setUserAgent(USER_AGENT)
|
||||
val headers = mapOf(
|
||||
"referer" to link.referer,
|
||||
"accept" to "*/*",
|
||||
"sec-ch-ua" to "\"Chromium\";v=\"91\", \" Not;A Brand\";v=\"99\"",
|
||||
"sec-ch-ua-mobile" to "?0",
|
||||
"sec-fetch-user" to "?1",
|
||||
"sec-fetch-mode" to "navigate",
|
||||
"sec-fetch-dest" to "video"
|
||||
) + link.headers // Adds the headers from the provider, e.g Authorization
|
||||
setDefaultRequestProperties(headers)
|
||||
|
||||
//https://stackoverflow.com/questions/69040127/error-code-io-bad-http-status-exoplayer-android
|
||||
setAllowCrossProtocolRedirects(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.createOfflineSource(): DataSource.Factory {
|
||||
return DefaultDataSourceFactory(this, USER_AGENT)
|
||||
}
|
||||
|
||||
private fun getSubSources(
|
||||
onlineSourceFactory: DataSource.Factory?,
|
||||
offlineSourceFactory: DataSource.Factory?,
|
||||
subHelper: PlayerSubtitleHelper,
|
||||
): Pair<List<SingleSampleMediaSource>, List<SubtitleData>> {
|
||||
val activeSubtitles = ArrayList<SubtitleData>()
|
||||
val subSources = subHelper.getAllSubtitles().mapNotNull { sub ->
|
||||
val subConfig = MediaItem.SubtitleConfiguration.Builder(Uri.parse(sub.url))
|
||||
.setMimeType(sub.mimeType)
|
||||
.setLanguage("_${sub.name}")
|
||||
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
|
||||
.build()
|
||||
when (sub.origin) {
|
||||
SubtitleOrigin.DOWNLOADED_FILE -> {
|
||||
if (offlineSourceFactory != null) {
|
||||
activeSubtitles.add(sub)
|
||||
SingleSampleMediaSource.Factory(offlineSourceFactory)
|
||||
.createMediaSource(subConfig, C.TIME_UNSET)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
SubtitleOrigin.URL -> {
|
||||
if (onlineSourceFactory != null) {
|
||||
activeSubtitles.add(sub)
|
||||
SingleSampleMediaSource.Factory(onlineSourceFactory)
|
||||
.createMediaSource(subConfig, C.TIME_UNSET)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
SubtitleOrigin.OPEN_SUBTITLES -> {
|
||||
// TODO
|
||||
throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
}
|
||||
println("SUBSRC: ${subSources.size} activeSubtitles : ${activeSubtitles.size} of ${subHelper.getAllSubtitles().size} ")
|
||||
return Pair(subSources, activeSubtitles)
|
||||
}
|
||||
|
||||
private fun getCache(context: Context, cacheSize: Long): SimpleCache? {
|
||||
return try {
|
||||
val databaseProvider = StandaloneDatabaseProvider(context)
|
||||
SimpleCache(
|
||||
File(
|
||||
context.cacheDir, "exoplayer"
|
||||
).also { it.deleteOnExit() }, // Ensures always fresh file
|
||||
LeastRecentlyUsedCacheEvictor(cacheSize),
|
||||
databaseProvider
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMediaItemBuilder(mimeType: String):
|
||||
MediaItem.Builder {
|
||||
return MediaItem.Builder()
|
||||
//Replace needed for android 6.0.0 https://github.com/google/ExoPlayer/issues/5983
|
||||
.setMimeType(mimeType)
|
||||
}
|
||||
|
||||
private fun getMediaItem(mimeType: String, uri: Uri): MediaItem {
|
||||
return getMediaItemBuilder(mimeType).setUri(uri).build()
|
||||
}
|
||||
|
||||
private fun getMediaItem(mimeType: String, url: String): MediaItem {
|
||||
return getMediaItemBuilder(mimeType).setUri(url).build()
|
||||
}
|
||||
|
||||
private fun getTrackSelector(context: Context): TrackSelector {
|
||||
val trackSelector = DefaultTrackSelector(context)
|
||||
trackSelector.parameters = DefaultTrackSelector.ParametersBuilder(context)
|
||||
// .setRendererDisabled(C.TRACK_TYPE_VIDEO, true)
|
||||
.setRendererDisabled(C.TRACK_TYPE_TEXT, true)
|
||||
.setDisabledTextTrackSelectionFlags(C.TRACK_TYPE_TEXT)
|
||||
.clearSelectionOverrides()
|
||||
.build()
|
||||
return trackSelector
|
||||
}
|
||||
|
||||
private fun buildExoPlayer(
|
||||
context: Context,
|
||||
mediaItem: MediaItem,
|
||||
subSources: List<SingleSampleMediaSource>,
|
||||
currentWindow: Int,
|
||||
playbackPosition: Long,
|
||||
playBackSpeed: Float,
|
||||
playWhenReady: Boolean = true,
|
||||
cacheFactory: CacheDataSource.Factory? = null,
|
||||
trackSelector: TrackSelector? = null,
|
||||
): ExoPlayer {
|
||||
val exoPlayerBuilder =
|
||||
ExoPlayer.Builder(context)
|
||||
.setTrackSelector(trackSelector ?: getTrackSelector(context))
|
||||
|
||||
val videoMediaSource =
|
||||
(if (cacheFactory == null) DefaultMediaSourceFactory(context) else DefaultMediaSourceFactory(
|
||||
cacheFactory
|
||||
)).createMediaSource(
|
||||
mediaItem
|
||||
)
|
||||
|
||||
return exoPlayerBuilder.build().apply {
|
||||
setPlayWhenReady(playWhenReady)
|
||||
seekTo(currentWindow, playbackPosition)
|
||||
setMediaSource(
|
||||
MergingMediaSource(
|
||||
videoMediaSource, *subSources.toTypedArray()
|
||||
),
|
||||
playbackPosition
|
||||
)
|
||||
setHandleAudioBecomingNoisy(true)
|
||||
setPlaybackSpeed(playBackSpeed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updatedTime() {
|
||||
val position = exoPlayer?.currentPosition
|
||||
val duration = exoPlayer?.contentDuration
|
||||
if (duration != null && position != null) {
|
||||
playerPositionChanged?.invoke(Pair(position, duration))
|
||||
}
|
||||
}
|
||||
|
||||
override fun seekTime(time: Long) {
|
||||
exoPlayer?.seekTime(time)
|
||||
}
|
||||
|
||||
override fun seekTo(time: Long) {
|
||||
updatedTime()
|
||||
exoPlayer?.seekTo(time)
|
||||
}
|
||||
|
||||
private fun ExoPlayer.seekTime(time: Long) {
|
||||
updatedTime()
|
||||
seekTo(currentPosition + time)
|
||||
}
|
||||
|
||||
override fun handleEvent(event: CSPlayerEvent) {
|
||||
Log.i(TAG, "handleEvent ${event.name}")
|
||||
try {
|
||||
exoPlayer?.apply {
|
||||
when (event) {
|
||||
CSPlayerEvent.Play -> {
|
||||
play()
|
||||
}
|
||||
CSPlayerEvent.Pause -> {
|
||||
pause()
|
||||
}
|
||||
CSPlayerEvent.ToggleMute -> {
|
||||
if (volume <= 0) {
|
||||
//is muted
|
||||
volume = lastMuteVolume
|
||||
} else {
|
||||
// is not muted
|
||||
lastMuteVolume = volume
|
||||
volume = 0f
|
||||
}
|
||||
}
|
||||
CSPlayerEvent.PlayPauseToggle -> {
|
||||
if (isPlaying) {
|
||||
pause()
|
||||
} else {
|
||||
play()
|
||||
}
|
||||
}
|
||||
CSPlayerEvent.SeekForward -> seekTime(seekActionTime)
|
||||
CSPlayerEvent.SeekBack -> seekTime(-seekActionTime)
|
||||
CSPlayerEvent.NextEpisode -> nextEpisode?.invoke()
|
||||
CSPlayerEvent.PrevEpisode -> prevEpisode?.invoke()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "handleEvent error", e)
|
||||
playerError?.invoke(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadExo(
|
||||
context: Context,
|
||||
mediaItem: MediaItem,
|
||||
subSources: List<SingleSampleMediaSource>,
|
||||
cacheFactory: CacheDataSource.Factory? = null
|
||||
) {
|
||||
Log.i(TAG, "loadExo")
|
||||
try {
|
||||
hasUsedFirstRender = false
|
||||
|
||||
// ye this has to be a val for whatever reason
|
||||
// this makes no sense
|
||||
exoPlayer = buildExoPlayer(
|
||||
context,
|
||||
mediaItem,
|
||||
subSources,
|
||||
currentWindow,
|
||||
playbackPosition,
|
||||
playBackSpeed,
|
||||
playWhenReady = isPlaying, // this keep the current state of the player
|
||||
cacheFactory = cacheFactory
|
||||
)
|
||||
|
||||
playerUpdated?.invoke(exoPlayer)
|
||||
exoPlayer?.prepare()
|
||||
|
||||
exoPlayer?.let { exo ->
|
||||
updateIsPlaying?.invoke(
|
||||
Pair(
|
||||
CSPlayerLoading.IsBuffering,
|
||||
CSPlayerLoading.IsBuffering
|
||||
)
|
||||
)
|
||||
isPlaying = exo.isPlaying
|
||||
}
|
||||
exoPlayer?.addListener(object : Player.Listener {
|
||||
/**
|
||||
* Records the current used subtitle/track. Needed as exoplayer seems to have loose track language selection.
|
||||
* */
|
||||
override fun onTracksInfoChanged(tracksInfo: TracksInfo) {
|
||||
exoPlayerSelectedTracks =
|
||||
tracksInfo.trackGroupInfos.mapNotNull { it.trackGroup.getFormat(0).language?.let { lang -> lang to it.isSelected } }
|
||||
super.onTracksInfoChanged(tracksInfo)
|
||||
}
|
||||
|
||||
override fun onCues(cues: MutableList<Cue>) {
|
||||
Log.i(TAG, "CUES: ${cues.size}")
|
||||
if(cues.size > 0) {
|
||||
Log.i(TAG, "CUES SAY: ${cues.first().text}")
|
||||
}
|
||||
super.onCues(cues)
|
||||
}
|
||||
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||
exoPlayer?.let { exo ->
|
||||
updateIsPlaying?.invoke(
|
||||
Pair(
|
||||
if (isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused,
|
||||
if (playbackState == Player.STATE_BUFFERING) CSPlayerLoading.IsBuffering else if (exo.isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused
|
||||
)
|
||||
)
|
||||
isPlaying = exo.isPlaying
|
||||
}
|
||||
|
||||
if (playWhenReady) {
|
||||
when (playbackState) {
|
||||
Player.STATE_READY -> {
|
||||
requestAutoFocus?.invoke()
|
||||
}
|
||||
Player.STATE_ENDED -> {
|
||||
handleEvent(CSPlayerEvent.NextEpisode)
|
||||
}
|
||||
Player.STATE_BUFFERING -> {
|
||||
updatedTime()
|
||||
}
|
||||
Player.STATE_IDLE -> {
|
||||
// IDLE
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
playerError?.invoke(error)
|
||||
|
||||
super.onPlayerError(error)
|
||||
}
|
||||
|
||||
override fun onRenderedFirstFrame() {
|
||||
updatedTime()
|
||||
if (!hasUsedFirstRender) { // this insures that we only call this once per player load
|
||||
Log.i(TAG, "Rendered first frame")
|
||||
setPreferredSubtitles(currentSubtitles)
|
||||
hasUsedFirstRender = true
|
||||
val format = exoPlayer?.videoFormat
|
||||
val width = format?.width
|
||||
val height = format?.height
|
||||
if (height != null && width != null) {
|
||||
playerDimensionsLoaded?.invoke(Pair(width, height))
|
||||
updatedTime()
|
||||
exoPlayer?.apply {
|
||||
requestedListeningPercentages?.forEach { percentage ->
|
||||
createMessage { _, _ ->
|
||||
updatedTime()
|
||||
}
|
||||
.setLooper(Looper.getMainLooper())
|
||||
.setPosition( /* positionMs= */contentDuration * percentage / 100)
|
||||
// .setPayload(customPayloadData)
|
||||
.setDeleteAfterDelivery(false)
|
||||
.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onRenderedFirstFrame()
|
||||
}
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "loadExo error", e)
|
||||
playerError?.invoke(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadOfflinePlayer(context: Context, data: ExtractorUri) {
|
||||
Log.i(TAG, "loadOfflinePlayer")
|
||||
try {
|
||||
currentDownloadedFile = data
|
||||
|
||||
val mediaItem = getMediaItem(MimeTypes.VIDEO_MP4, data.uri)
|
||||
val offlineSourceFactory = context.createOfflineSource()
|
||||
val (subSources, activeSubtitles) = getSubSources(
|
||||
offlineSourceFactory,
|
||||
offlineSourceFactory,
|
||||
subtitleHelper
|
||||
)
|
||||
subtitleHelper.setActiveSubtitles(activeSubtitles.toSet())
|
||||
loadExo(context, mediaItem, subSources)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "loadOfflinePlayer error", e)
|
||||
playerError?.invoke(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadOnlinePlayer(context: Context, link: ExtractorLink) {
|
||||
Log.i(TAG, "loadOnlinePlayer")
|
||||
try {
|
||||
currentLink = link
|
||||
|
||||
if (ignoreSSL) {
|
||||
// Disables ssl check
|
||||
val sslContext: SSLContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(null, arrayOf(SSLTrustManager()), java.security.SecureRandom())
|
||||
sslContext.createSSLEngine()
|
||||
HttpsURLConnection.setDefaultHostnameVerifier { _: String, _: SSLSession ->
|
||||
true
|
||||
}
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)
|
||||
}
|
||||
|
||||
val mime = if (link.isM3u8) {
|
||||
MimeTypes.APPLICATION_M3U8
|
||||
} else {
|
||||
MimeTypes.VIDEO_MP4
|
||||
}
|
||||
val mediaItem = getMediaItem(mime, link.url)
|
||||
|
||||
val onlineSourceFactory = createOnlineSource(link)
|
||||
val offlineSourceFactory = context.createOfflineSource()
|
||||
|
||||
val (subSources, activeSubtitles) = getSubSources(
|
||||
onlineSourceFactory,
|
||||
offlineSourceFactory,
|
||||
subtitleHelper
|
||||
)
|
||||
subtitleHelper.setActiveSubtitles(activeSubtitles.toSet())
|
||||
|
||||
simpleCache = getCache(context, cacheSize)
|
||||
|
||||
val cacheFactory = CacheDataSource.Factory().apply {
|
||||
simpleCache?.let { setCache(it) }
|
||||
setUpstreamDataSourceFactory(onlineSourceFactory)
|
||||
}
|
||||
|
||||
loadExo(context, mediaItem, subSources, cacheFactory)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "loadOnlinePlayer error", e)
|
||||
playerError?.invoke(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun reloadPlayer(context: Context) {
|
||||
Log.i(TAG, "reloadPlayer")
|
||||
|
||||
exoPlayer?.release()
|
||||
currentLink?.let {
|
||||
loadOnlinePlayer(context, it)
|
||||
} ?: currentDownloadedFile?.let {
|
||||
loadOfflinePlayer(context, it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class DownloadFileGenerator(
|
||||
private val episodes: List<ExtractorUri>,
|
||||
private var currentIndex: Int = 0
|
||||
) : IGenerator {
|
||||
override val hasCache = false
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return currentIndex < episodes.size - 1
|
||||
}
|
||||
|
||||
override fun hasPrev(): Boolean {
|
||||
return currentIndex > 0
|
||||
}
|
||||
|
||||
override fun next() {
|
||||
if (hasNext())
|
||||
currentIndex++
|
||||
}
|
||||
|
||||
override fun prev() {
|
||||
if (hasPrev())
|
||||
currentIndex--
|
||||
}
|
||||
|
||||
override fun goto(index: Int) {
|
||||
// clamps value
|
||||
currentIndex = min(episodes.size - 1, max(0, index))
|
||||
}
|
||||
|
||||
override fun getCurrentId(): Int? {
|
||||
return episodes[currentIndex].id
|
||||
}
|
||||
|
||||
override fun getCurrent(): Any {
|
||||
return episodes[currentIndex]
|
||||
}
|
||||
|
||||
override fun generateLinks(
|
||||
clearCache: Boolean,
|
||||
isCasting: Boolean,
|
||||
callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,
|
||||
subtitleCallback: (SubtitleData) -> Unit
|
||||
): Boolean {
|
||||
val meta = episodes[currentIndex]
|
||||
callback(Pair(null, meta))
|
||||
|
||||
context?.let { ctx ->
|
||||
val relative = meta.relativePath
|
||||
val display = meta.displayName
|
||||
|
||||
if (display == null || relative == null) {
|
||||
return@let
|
||||
}
|
||||
VideoDownloadManager.getFolder(ctx, relative, meta.basePath)
|
||||
?.forEach { file ->
|
||||
val name = display.removeSuffix(".mp4")
|
||||
if (file.first != meta.displayName && file.first.startsWith(name)) {
|
||||
val realName = file.first.removePrefix(name)
|
||||
.removeSuffix(".vtt")
|
||||
.removeSuffix(".srt")
|
||||
.removeSuffix(".txt")
|
||||
|
||||
subtitleCallback(
|
||||
SubtitleData(
|
||||
realName.ifBlank { ctx.getString(R.string.default_subtitles) },
|
||||
file.second.toString(),
|
||||
SubtitleOrigin.DOWNLOADED_FILE,
|
||||
name.toSubtitleMimeType()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getUri
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import java.io.File
|
||||
|
||||
const val DTAG = "PlayerActivity"
|
||||
|
||||
class DownloadedPlayerActivity : AppCompatActivity() {
|
||||
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
||||
CommonActivity.dispatchKeyEvent(this, event)?.let {
|
||||
return it
|
||||
}
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
CommonActivity.onKeyDown(this, keyCode, event)
|
||||
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
override fun onUserLeaveHint() {
|
||||
super.onUserLeaveHint()
|
||||
CommonActivity.onUserLeaveHint(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Log.i(DTAG, "onCreate")
|
||||
|
||||
CommonActivity.loadThemes(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
CommonActivity.init(this)
|
||||
|
||||
val data = intent.data
|
||||
if (data == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
val uri = getUri(intent.data)
|
||||
if (uri == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
val path = uri.path
|
||||
// Because it doesn't get the path when it's downloaded, I have no idea
|
||||
val realPath = if (File(
|
||||
intent.data?.path?.removePrefix("/file") ?: "NONE"
|
||||
).exists()
|
||||
) intent.data?.path?.removePrefix("/file") else path
|
||||
|
||||
if (realPath == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
val name = try {
|
||||
File(realPath).name
|
||||
} catch (e: Exception) {
|
||||
"NULL"
|
||||
}
|
||||
|
||||
val realUri = AppUtils.getVideoContentUri(this, realPath)
|
||||
val tryUri = realUri ?: uri
|
||||
|
||||
setContentView(R.layout.empty_layout)
|
||||
Log.i(DTAG, "navigating")
|
||||
|
||||
//TODO add relative path for subs
|
||||
this.navigate(
|
||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||
DownloadFileGenerator(listOf(ExtractorUri(uri = tryUri, name = name)))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,490 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||
import kotlinx.android.synthetic.main.fragment_player.*
|
||||
import kotlinx.android.synthetic.main.player_custom_layout.*
|
||||
|
||||
// TODO Auto select subtitles
|
||||
class GeneratorPlayer : FullScreenPlayer() {
|
||||
companion object {
|
||||
private var lastUsedGenerator: IGenerator? = null
|
||||
fun newInstance(generator: IGenerator): Bundle {
|
||||
lastUsedGenerator = generator
|
||||
return Bundle()
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var viewModel: PlayerGeneratorViewModel //by activityViewModels()
|
||||
private var currentLinks: Set<Pair<ExtractorLink?, ExtractorUri?>> = setOf()
|
||||
private var currentSubs: Set<SubtitleData> = setOf()
|
||||
|
||||
private var currentSelectedLink: Pair<ExtractorLink?, ExtractorUri?>? = null
|
||||
private var currentSelectedSubtitles: SubtitleData? = null
|
||||
private var currentMeta: Any? = null
|
||||
private var nextMeta: Any? = null
|
||||
private var isActive: Boolean = false
|
||||
private var isNextEpisode: Boolean = false // this is used to reset the watch time
|
||||
|
||||
private fun startLoading() {
|
||||
player.release()
|
||||
currentSelectedSubtitles = null
|
||||
isActive = false
|
||||
overlay_loading_skip_button?.isVisible = false
|
||||
player_loading_overlay?.isVisible = true
|
||||
}
|
||||
|
||||
private fun setSubtitles(sub: SubtitleData?): Boolean {
|
||||
currentSelectedSubtitles = sub
|
||||
return player.setPreferredSubtitles(sub)
|
||||
}
|
||||
|
||||
private fun noSubtitles(): Boolean {
|
||||
return setSubtitles(null)
|
||||
}
|
||||
|
||||
private fun loadLink(link: Pair<ExtractorLink?, ExtractorUri?>?, sameEpisode: Boolean) {
|
||||
if (link == null) return
|
||||
|
||||
// manage UI
|
||||
player_loading_overlay?.isVisible = false
|
||||
uiReset()
|
||||
currentSelectedLink = link
|
||||
currentMeta = viewModel.getMeta()
|
||||
nextMeta = viewModel.getNextMeta()
|
||||
isActive = true
|
||||
setPlayerDimen(null)
|
||||
setTitle()
|
||||
|
||||
// load player
|
||||
context?.let { ctx ->
|
||||
val (url, uri) = link
|
||||
player.loadPlayer(
|
||||
ctx,
|
||||
sameEpisode,
|
||||
url,
|
||||
uri,
|
||||
startPosition = if (sameEpisode) null else {
|
||||
if (isNextEpisode) 0L else (DataStoreHelper.getViewPos(viewModel.getId())?.position
|
||||
?: 0L)
|
||||
},
|
||||
currentSubs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortLinks(useQualitySettings: Boolean = true): List<Pair<ExtractorLink?, ExtractorUri?>> {
|
||||
return currentLinks.sortedBy {
|
||||
val (linkData, _) = it
|
||||
var quality = linkData?.quality ?: Qualities.Unknown.value
|
||||
|
||||
// we set all qualities above current max as max -1
|
||||
if (useQualitySettings && quality > currentPrefQuality) {
|
||||
quality = currentPrefQuality - 1
|
||||
}
|
||||
// negative because we want to sort highest quality first
|
||||
-(quality)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSubPicker() {
|
||||
subsPathPicker.launch(
|
||||
arrayOf(
|
||||
"text/vtt",
|
||||
"application/x-subrip",
|
||||
"text/plain",
|
||||
"text/str",
|
||||
"application/octet-stream"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Open file picker
|
||||
private val subsPathPicker =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
|
||||
normalSafeApiCall {
|
||||
// It lies, it can be null if file manager quits.
|
||||
if (uri == null) return@normalSafeApiCall
|
||||
val ctx = context ?: AcraApplication.context ?: return@normalSafeApiCall
|
||||
// RW perms for the path
|
||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
|
||||
ctx.contentResolver.takePersistableUriPermission(uri, flags)
|
||||
|
||||
val file = UniFile.fromUri(ctx, uri)
|
||||
println("Loaded subtitle file. Selected URI path: $uri - Name: ${file.name}")
|
||||
// DO NOT REMOVE THE FILE EXTENSION FROM NAME, IT'S NEEDED FOR MIME TYPES
|
||||
val name = file.name ?: uri.toString()
|
||||
|
||||
val subtitleData = SubtitleData(
|
||||
name,
|
||||
uri.toString(),
|
||||
SubtitleOrigin.DOWNLOADED_FILE,
|
||||
name.toSubtitleMimeType()
|
||||
)
|
||||
|
||||
setSubtitles(subtitleData)
|
||||
|
||||
// this is used instead of observe, because observe is too slow
|
||||
val subs = currentSubs.toMutableSet()
|
||||
subs.add(subtitleData)
|
||||
player.setActiveSubtitles(subs)
|
||||
player.reloadPlayer(ctx)
|
||||
|
||||
viewModel.addSubtitles(setOf(subtitleData))
|
||||
|
||||
selectSourceDialog?.dismissSafe()
|
||||
|
||||
showToast(
|
||||
activity,
|
||||
String.format(ctx.getString(R.string.player_loaded_subtitles), name),
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var selectSourceDialog: AlertDialog? = null
|
||||
override fun showMirrorsDialogue() {
|
||||
currentSelectedSubtitles = player.getCurrentPreferredSubtitle()
|
||||
context?.let { ctx ->
|
||||
val isPlaying = player.getIsPlaying()
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
val currentSubtitles = sortSubs(currentSubs)
|
||||
|
||||
val sourceBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack)
|
||||
.setView(R.layout.player_select_source_and_subs)
|
||||
|
||||
val sourceDialog = sourceBuilder.create()
|
||||
selectSourceDialog = sourceDialog
|
||||
sourceDialog.show()
|
||||
val providerList =
|
||||
sourceDialog.findViewById<ListView>(R.id.sort_providers)!!
|
||||
val subtitleList =
|
||||
sourceDialog.findViewById<ListView>(R.id.sort_subtitles)!!
|
||||
val applyButton =
|
||||
sourceDialog.findViewById<MaterialButton>(R.id.apply_btt)!!
|
||||
val cancelButton =
|
||||
sourceDialog.findViewById<MaterialButton>(R.id.cancel_btt)!!
|
||||
|
||||
val footer: TextView =
|
||||
layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView
|
||||
footer.text = ctx.getString(R.string.player_load_subtitles)
|
||||
footer.setOnClickListener {
|
||||
openSubPicker()
|
||||
}
|
||||
subtitleList.addFooterView(footer)
|
||||
|
||||
var sourceIndex = 0
|
||||
var startSource = 0
|
||||
|
||||
val sortedUrls = sortLinks(useQualitySettings = false)
|
||||
if (sortedUrls.isNullOrEmpty()) {
|
||||
sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone = true
|
||||
} else {
|
||||
startSource = sortedUrls.indexOf(currentSelectedLink)
|
||||
sourceIndex = startSource
|
||||
|
||||
val sourcesArrayAdapter =
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
||||
sourcesArrayAdapter.addAll(sortedUrls.map {
|
||||
it.first?.name ?: it.second?.name ?: "NULL"
|
||||
})
|
||||
|
||||
providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
providerList.adapter = sourcesArrayAdapter
|
||||
providerList.setSelection(sourceIndex)
|
||||
providerList.setItemChecked(sourceIndex, true)
|
||||
|
||||
providerList.setOnItemClickListener { _, _, which, _ ->
|
||||
sourceIndex = which
|
||||
providerList.setItemChecked(which, true)
|
||||
}
|
||||
}
|
||||
|
||||
sourceDialog.setOnDismissListener {
|
||||
if (isPlaying) {
|
||||
player.handleEvent(CSPlayerEvent.Play)
|
||||
}
|
||||
activity?.hideSystemUI()
|
||||
selectSourceDialog = null
|
||||
}
|
||||
|
||||
val subtitleIndexStart = currentSubtitles.indexOf(currentSelectedSubtitles) + 1
|
||||
var subtitleIndex = subtitleIndexStart
|
||||
|
||||
val subsArrayAdapter =
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
subsArrayAdapter.add(getString(R.string.no_subtitles))
|
||||
subsArrayAdapter.addAll(currentSubtitles.map { it.name })
|
||||
|
||||
subtitleList.adapter = subsArrayAdapter
|
||||
subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
|
||||
subtitleList.setSelection(subtitleIndex)
|
||||
subtitleList.setItemChecked(subtitleIndex, true)
|
||||
|
||||
subtitleList.setOnItemClickListener { _, _, which, _ ->
|
||||
subtitleIndex = which
|
||||
subtitleList.setItemChecked(which, true)
|
||||
}
|
||||
|
||||
cancelButton.setOnClickListener {
|
||||
sourceDialog.dismissSafe(activity)
|
||||
}
|
||||
|
||||
applyButton.setOnClickListener {
|
||||
var init = false
|
||||
if (sourceIndex != startSource) {
|
||||
init = true
|
||||
}
|
||||
if (subtitleIndex != subtitleIndexStart) {
|
||||
init = init || if (subtitleIndex <= 0) {
|
||||
noSubtitles()
|
||||
} else {
|
||||
setSubtitles(currentSubtitles[subtitleIndex - 1])
|
||||
}
|
||||
}
|
||||
if (init) {
|
||||
loadLink(sortedUrls[sourceIndex], true)
|
||||
}
|
||||
sourceDialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun noLinksFound() {
|
||||
showToast(activity, R.string.no_links_found_toast, Toast.LENGTH_SHORT)
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
private fun startPlayer() {
|
||||
if (isActive) return // we don't want double load when you skip loading
|
||||
|
||||
val links = sortLinks()
|
||||
if (links.isEmpty()) {
|
||||
noLinksFound()
|
||||
return
|
||||
}
|
||||
loadLink(links.first(), false)
|
||||
}
|
||||
|
||||
override fun nextEpisode() {
|
||||
isNextEpisode = true
|
||||
viewModel.loadLinksNext()
|
||||
}
|
||||
|
||||
override fun prevEpisode() {
|
||||
isNextEpisode = true
|
||||
viewModel.loadLinksPrev()
|
||||
}
|
||||
|
||||
override fun nextMirror() {
|
||||
val links = sortLinks()
|
||||
if (links.isEmpty()) {
|
||||
noLinksFound()
|
||||
return
|
||||
}
|
||||
|
||||
val newIndex = links.indexOf(currentSelectedLink) + 1
|
||||
if (newIndex >= links.size) {
|
||||
noLinksFound()
|
||||
return
|
||||
}
|
||||
|
||||
loadLink(links[newIndex], true)
|
||||
}
|
||||
|
||||
override fun playerPositionChanged(posDur: Pair<Long, Long>) {
|
||||
val (position, duration) = posDur
|
||||
viewModel.getId()?.let {
|
||||
DataStoreHelper.setViewPos(it, position, duration)
|
||||
}
|
||||
val percentage = position * 100L / duration
|
||||
|
||||
val nextEp = percentage >= NEXT_WATCH_EPISODE_PERCENTAGE
|
||||
val resumeMeta = if (nextEp) nextMeta else currentMeta
|
||||
if (resumeMeta == null && nextEp) {
|
||||
// remove last watched as it is the last episode and you have watched too much
|
||||
when (val newMeta = currentMeta) {
|
||||
is ResultEpisode -> {
|
||||
DataStoreHelper.removeLastWatched(newMeta.parentId)
|
||||
}
|
||||
is ExtractorUri -> {
|
||||
DataStoreHelper.removeLastWatched(newMeta.parentId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// save resume
|
||||
when (resumeMeta) {
|
||||
is ResultEpisode -> {
|
||||
DataStoreHelper.setLastWatched(
|
||||
resumeMeta.parentId,
|
||||
resumeMeta.id,
|
||||
resumeMeta.episode,
|
||||
resumeMeta.season,
|
||||
isFromDownload = false
|
||||
)
|
||||
}
|
||||
is ExtractorUri -> {
|
||||
DataStoreHelper.setLastWatched(
|
||||
resumeMeta.parentId,
|
||||
resumeMeta.id,
|
||||
resumeMeta.episode,
|
||||
resumeMeta.season,
|
||||
isFromDownload = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isOpVisible = false
|
||||
when (val meta = currentMeta) {
|
||||
is ResultEpisode -> {
|
||||
if (meta.tvType.isAnimeOp())
|
||||
isOpVisible = percentage < SKIP_OP_VIDEO_PERCENTAGE
|
||||
}
|
||||
}
|
||||
player_skip_op?.isVisible = isOpVisible
|
||||
player_skip_episode?.isVisible = !isOpVisible && viewModel.hasNextEpisode() == true
|
||||
|
||||
if (percentage > PRELOAD_NEXT_EPISODE_PERCENTAGE) {
|
||||
viewModel.preLoadNextLinks()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun setTitle() {
|
||||
var headerName: String? = null
|
||||
var episode: Int? = null
|
||||
var season: Int? = null
|
||||
var tvType: TvType? = null
|
||||
|
||||
when (val meta = currentMeta) {
|
||||
is ResultEpisode -> {
|
||||
headerName = meta.headerName
|
||||
episode = meta.episode
|
||||
season = meta.season
|
||||
tvType = meta.tvType
|
||||
}
|
||||
is ExtractorUri -> {
|
||||
headerName = meta.headerName
|
||||
episode = meta.episode
|
||||
season = meta.season
|
||||
tvType = meta.tvType
|
||||
}
|
||||
}
|
||||
|
||||
player_video_title?.text = if (headerName != null) {
|
||||
headerName +
|
||||
if (tvType.isEpisodeBased() && episode != null)
|
||||
if (season == null)
|
||||
" - ${getString(R.string.episode)} $episode"
|
||||
else
|
||||
" \"${getString(R.string.season_short)}${season}:${getString(R.string.episode_short)}${episode}\""
|
||||
else ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun setPlayerDimen(widthHeight: Pair<Int, Int>?) {
|
||||
val extra = if (widthHeight != null) {
|
||||
val (width, height) = widthHeight
|
||||
" - ${width}x${height}"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
player_video_title_rez?.text =
|
||||
(currentSelectedLink?.first?.name ?: currentSelectedLink?.second?.name
|
||||
?: "NULL") + extra
|
||||
}
|
||||
|
||||
override fun playerDimensionsLoaded(widthHeight: Pair<Int, Int>) {
|
||||
setPlayerDimen(widthHeight)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]
|
||||
viewModel.attachGenerator(lastUsedGenerator)
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (currentSelectedLink == null) {
|
||||
viewModel.loadLinks()
|
||||
}
|
||||
|
||||
overlay_loading_skip_button?.setOnClickListener {
|
||||
startPlayer()
|
||||
}
|
||||
|
||||
player_loading_go_back?.setOnClickListener {
|
||||
player.release()
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
observe(viewModel.loadingLinks) {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
startLoading()
|
||||
}
|
||||
is Resource.Success -> {
|
||||
// provider returned false
|
||||
//if (it.value != true) {
|
||||
// showToast(activity, R.string.unexpected_error, Toast.LENGTH_SHORT)
|
||||
//}
|
||||
startPlayer()
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
showToast(activity, it.errorString, Toast.LENGTH_LONG)
|
||||
startPlayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.currentLinks) {
|
||||
currentLinks = it
|
||||
overlay_loading_skip_button?.isVisible = it.isNotEmpty()
|
||||
}
|
||||
|
||||
observe(viewModel.currentSubs) {
|
||||
currentSubs = it
|
||||
player.setActiveSubtitles(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
|
||||
interface IGenerator {
|
||||
val hasCache: Boolean
|
||||
|
||||
fun hasNext(): Boolean
|
||||
fun hasPrev(): Boolean
|
||||
fun next()
|
||||
fun prev()
|
||||
fun goto(index: Int)
|
||||
|
||||
fun getCurrentId(): Int? // this is used to save data or read data about this id
|
||||
fun getCurrent(): Any? // this is used to get metadata about the current playing, can return null
|
||||
|
||||
/* not safe, must use try catch */
|
||||
fun generateLinks(
|
||||
clearCache: Boolean,
|
||||
isCasting: Boolean,
|
||||
callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,
|
||||
subtitleCallback: (SubtitleData) -> Unit
|
||||
): Boolean
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.content.Context
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
|
||||
enum class PlayerEventType(val value: Int) {
|
||||
//Stop(-1),
|
||||
Pause(0),
|
||||
Play(1),
|
||||
SeekForward(2),
|
||||
SeekBack(3),
|
||||
|
||||
//SkipCurrentChapter(4),
|
||||
NextEpisode(5),
|
||||
PrevEpisode(5),
|
||||
PlayPauseToggle(7),
|
||||
ToggleMute(8),
|
||||
Lock(9),
|
||||
ToggleHide(10),
|
||||
ShowSpeed(11),
|
||||
ShowMirrors(12),
|
||||
Resize(13),
|
||||
}
|
||||
|
||||
enum class CSPlayerEvent(val value: Int) {
|
||||
Pause(0),
|
||||
Play(1),
|
||||
SeekForward(2),
|
||||
SeekBack(3),
|
||||
|
||||
//SkipCurrentChapter(4),
|
||||
NextEpisode(5),
|
||||
PrevEpisode(6),
|
||||
PlayPauseToggle(7),
|
||||
ToggleMute(8),
|
||||
}
|
||||
|
||||
enum class CSPlayerLoading {
|
||||
IsPaused,
|
||||
IsPlaying,
|
||||
IsBuffering,
|
||||
//IsDone,
|
||||
}
|
||||
|
||||
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
||||
const val STATE_RESUME_WINDOW = "resumeWindow"
|
||||
const val STATE_RESUME_POSITION = "resumePosition"
|
||||
const val STATE_PLAYER_FULLSCREEN = "playerFullscreen"
|
||||
const val STATE_PLAYER_PLAYING = "playerOnPlay"
|
||||
const val ACTION_MEDIA_CONTROL = "media_control"
|
||||
const val EXTRA_CONTROL_TYPE = "control_type"
|
||||
const val PLAYBACK_SPEED = "playback_speed"
|
||||
const val RESIZE_MODE_KEY = "resize_mode" // Last used resize mode
|
||||
const val PLAYBACK_SPEED_KEY = "playback_speed" // Last used playback speed
|
||||
const val PREFERRED_SUBS_KEY = "preferred_subtitles" // Last used resize mode
|
||||
const val PLAYBACK_FASTFORWARD = "playback_fastforward" // Last used resize mode
|
||||
|
||||
/** Abstract Exoplayer logic, can be expanded to other players */
|
||||
interface IPlayer {
|
||||
fun getPlaybackSpeed(): Float
|
||||
fun setPlaybackSpeed(speed: Float)
|
||||
|
||||
fun getIsPlaying(): Boolean
|
||||
fun getDuration(): Long?
|
||||
fun getPosition(): Long?
|
||||
|
||||
fun seekTime(time: Long)
|
||||
fun seekTo(time: Long)
|
||||
|
||||
fun initCallbacks(
|
||||
playerUpdated: (Any?) -> Unit, // attach player to view
|
||||
updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)? = null, // (wasPlaying, isPlaying)
|
||||
requestAutoFocus: (() -> Unit)? = null, // current player starts, asking for all other programs to shut the fuck up
|
||||
playerError: ((Exception) -> Unit)? = null, // player error when rendering or misc, used to display toast or log
|
||||
playerDimensionsLoaded: ((Pair<Int, Int>) -> Unit)? = null, // (with, height), for UI
|
||||
requestedListeningPercentages: List<Int>? = null, // this is used to request when the player should report back view percentage
|
||||
playerPositionChanged: ((Pair<Long, Long>) -> Unit)? = null,// (position, duration) this is used to update UI based of the current time
|
||||
nextEpisode: (() -> Unit)? = null, // this is used by the player to load the next episode
|
||||
prevEpisode: (() -> Unit)? = null, // this is used by the player to load the previous episode
|
||||
)
|
||||
|
||||
fun updateSubtitleStyle(style: SaveCaptionStyle)
|
||||
fun loadPlayer(
|
||||
context: Context,
|
||||
sameEpisode: Boolean,
|
||||
link: ExtractorLink? = null,
|
||||
data: ExtractorUri? = null,
|
||||
startPosition: Long? = null,
|
||||
subtitles : Set<SubtitleData>,
|
||||
)
|
||||
|
||||
fun reloadPlayer(context: Context)
|
||||
|
||||
fun setActiveSubtitles(subtitles : Set<SubtitleData>)
|
||||
fun setPreferredSubtitles(subtitle : SubtitleData?) : Boolean // returns true if the player requires a reload, null for nothing
|
||||
fun getCurrentPreferredSubtitle() : SubtitleData?
|
||||
|
||||
fun handleEvent(event: CSPlayerEvent)
|
||||
|
||||
fun onStop()
|
||||
fun onPause()
|
||||
fun onResume(context: Context)
|
||||
|
||||
fun release()
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,109 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class PlayerGeneratorViewModel : ViewModel() {
|
||||
private var generator: IGenerator? = null
|
||||
|
||||
private val _currentLinks = MutableLiveData<Set<Pair<ExtractorLink?, ExtractorUri?>>>(setOf())
|
||||
val currentLinks: LiveData<Set<Pair<ExtractorLink?, ExtractorUri?>>> = _currentLinks
|
||||
|
||||
private val _currentSubs = MutableLiveData<Set<SubtitleData>>(setOf())
|
||||
val currentSubs: LiveData<Set<SubtitleData>> = _currentSubs
|
||||
|
||||
private val _loadingLinks = MutableLiveData<Resource<Boolean?>>()
|
||||
val loadingLinks: LiveData<Resource<Boolean?>> = _loadingLinks
|
||||
|
||||
fun getId(): Int? {
|
||||
return generator?.getCurrentId()
|
||||
}
|
||||
|
||||
fun loadLinks(episode: Int) {
|
||||
generator?.goto(episode)
|
||||
loadLinks()
|
||||
}
|
||||
|
||||
fun loadLinksPrev() {
|
||||
if (generator?.hasPrev() == true) {
|
||||
generator?.prev()
|
||||
loadLinks()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadLinksNext() {
|
||||
if (generator?.hasNext() == true) {
|
||||
generator?.next()
|
||||
loadLinks()
|
||||
}
|
||||
}
|
||||
|
||||
fun hasNextEpisode(): Boolean? {
|
||||
return generator?.hasNext()
|
||||
}
|
||||
|
||||
fun preLoadNextLinks() = viewModelScope.launch {
|
||||
normalSafeApiCall {
|
||||
if (generator?.hasCache == true && generator?.hasNext() == true) {
|
||||
generator?.next()
|
||||
generator?.generateLinks(clearCache = false, isCasting = false, {}, {})
|
||||
generator?.prev()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMeta(): Any? {
|
||||
return normalSafeApiCall { generator?.getCurrent() }
|
||||
}
|
||||
|
||||
fun getNextMeta(): Any? {
|
||||
return normalSafeApiCall {
|
||||
if (generator?.hasNext() == false) return@normalSafeApiCall null
|
||||
generator?.next()
|
||||
val next = generator?.getCurrent()
|
||||
generator?.prev()
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
fun attachGenerator(newGenerator: IGenerator?) {
|
||||
if (generator == null) {
|
||||
generator = newGenerator
|
||||
}
|
||||
}
|
||||
|
||||
fun addSubtitles(file: Set<SubtitleData>) {
|
||||
val subs = (_currentSubs.value?.toMutableSet() ?: mutableSetOf())
|
||||
subs.addAll(file)
|
||||
_currentSubs.postValue(subs)
|
||||
}
|
||||
|
||||
fun loadLinks(clearCache: Boolean = false, isCasting: Boolean = false) = viewModelScope.launch {
|
||||
val currentLinks = mutableSetOf<Pair<ExtractorLink?, ExtractorUri?>>()
|
||||
val currentSubs = mutableSetOf<SubtitleData>()
|
||||
|
||||
_loadingLinks.postValue(Resource.Loading())
|
||||
val loadingState = safeApiCall {
|
||||
generator?.generateLinks(clearCache = clearCache, isCasting = isCasting, {
|
||||
currentLinks.add(it)
|
||||
_currentLinks.postValue(currentLinks)
|
||||
}, {
|
||||
currentSubs.add(it)
|
||||
_currentSubs.postValue(currentSubs)
|
||||
})
|
||||
}
|
||||
|
||||
_loadingLinks.postValue(loadingState)
|
||||
|
||||
_currentLinks.postValue(currentLinks)
|
||||
_currentSubs.postValue(currentSubs)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.app.PictureInPictureParams
|
||||
import android.app.RemoteAction
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import com.lagradost.cloudstream3.R
|
||||
|
||||
class PlayerPipHelper {
|
||||
companion object {
|
||||
private fun getPen(activity: Activity, code: Int): PendingIntent {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
PendingIntent.getBroadcast(
|
||||
activity,
|
||||
code,
|
||||
Intent("media_control").putExtra("control_type", code),
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
} else {
|
||||
PendingIntent.getBroadcast(
|
||||
activity,
|
||||
code,
|
||||
Intent("media_control").putExtra("control_type", code),
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun getRemoteAction(
|
||||
activity: Activity,
|
||||
id: Int,
|
||||
@StringRes title: Int,
|
||||
event: CSPlayerEvent
|
||||
): RemoteAction {
|
||||
val text = activity.getString(title)
|
||||
return RemoteAction(
|
||||
Icon.createWithResource(activity, id),
|
||||
text,
|
||||
text,
|
||||
getPen(activity, event.value)
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun updatePIPModeActions(activity: Activity, isPlaying: Boolean) {
|
||||
val actions: ArrayList<RemoteAction> = ArrayList()
|
||||
actions.add(
|
||||
getRemoteAction(
|
||||
activity,
|
||||
R.drawable.go_back_30,
|
||||
R.string.go_back_30,
|
||||
CSPlayerEvent.SeekBack
|
||||
)
|
||||
)
|
||||
|
||||
if (isPlaying) {
|
||||
actions.add(
|
||||
getRemoteAction(
|
||||
activity,
|
||||
R.drawable.netflix_pause,
|
||||
R.string.pause,
|
||||
CSPlayerEvent.Pause
|
||||
)
|
||||
)
|
||||
} else {
|
||||
actions.add(
|
||||
getRemoteAction(
|
||||
activity,
|
||||
R.drawable.ic_baseline_play_arrow_24,
|
||||
R.string.pause,
|
||||
CSPlayerEvent.Play
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
actions.add(
|
||||
getRemoteAction(
|
||||
activity,
|
||||
R.drawable.go_forward_30,
|
||||
R.string.go_forward_30,
|
||||
CSPlayerEvent.SeekForward
|
||||
)
|
||||
)
|
||||
activity.setPictureInPictureParams(
|
||||
PictureInPictureParams.Builder().setActions(actions).build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import com.google.android.exoplayer2.ui.SubtitleView
|
||||
import com.google.android.exoplayer2.util.MimeTypes
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.fromSaveToStyle
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
|
||||
enum class SubtitleStatus {
|
||||
IS_ACTIVE,
|
||||
REQUIRES_RELOAD,
|
||||
NOT_FOUND,
|
||||
}
|
||||
|
||||
enum class SubtitleOrigin {
|
||||
URL,
|
||||
DOWNLOADED_FILE,
|
||||
OPEN_SUBTITLES,
|
||||
}
|
||||
|
||||
data class SubtitleData(
|
||||
val name: String,
|
||||
val url: String,
|
||||
val origin: SubtitleOrigin,
|
||||
val mimeType: String,
|
||||
)
|
||||
|
||||
class PlayerSubtitleHelper {
|
||||
private var activeSubtitles: Set<SubtitleData> = emptySet()
|
||||
private var allSubtitles: Set<SubtitleData> = emptySet()
|
||||
|
||||
fun getAllSubtitles(): Set<SubtitleData> {
|
||||
return allSubtitles
|
||||
}
|
||||
|
||||
fun setActiveSubtitles(list: Set<SubtitleData>) {
|
||||
activeSubtitles = list
|
||||
}
|
||||
|
||||
fun setAllSubtitles(list: Set<SubtitleData>) {
|
||||
allSubtitles = list
|
||||
}
|
||||
|
||||
private var subStyle: SaveCaptionStyle? = null
|
||||
private var subtitleView: SubtitleView? = null
|
||||
|
||||
companion object {
|
||||
fun String.toSubtitleMimeType(): String {
|
||||
return when {
|
||||
endsWith("vtt", true) -> MimeTypes.TEXT_VTT
|
||||
endsWith("srt", true) -> MimeTypes.APPLICATION_SUBRIP
|
||||
endsWith("xml", true) || endsWith("ttml", true) -> MimeTypes.APPLICATION_TTML
|
||||
else -> MimeTypes.APPLICATION_SUBRIP // TODO get request to see
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSubtitleMimeType(context: Context, url: String, origin: SubtitleOrigin): String {
|
||||
return when (origin) {
|
||||
// The url can look like .../document/4294 when the name is EnglishSDH.srt
|
||||
SubtitleOrigin.DOWNLOADED_FILE -> {
|
||||
UniFile.fromUri(
|
||||
context,
|
||||
Uri.parse(url)
|
||||
).name?.toSubtitleMimeType() ?: MimeTypes.APPLICATION_SUBRIP
|
||||
}
|
||||
SubtitleOrigin.URL -> {
|
||||
return url.toSubtitleMimeType()
|
||||
}
|
||||
SubtitleOrigin.OPEN_SUBTITLES -> {
|
||||
// TODO
|
||||
throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSubtitleData(subtitleFile: SubtitleFile): SubtitleData {
|
||||
return SubtitleData(
|
||||
name = subtitleFile.lang,
|
||||
url = subtitleFile.url,
|
||||
origin = SubtitleOrigin.URL,
|
||||
mimeType = subtitleFile.url.toSubtitleMimeType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun subtitleStatus(sub : SubtitleData?): SubtitleStatus {
|
||||
if(activeSubtitles.contains(sub)) {
|
||||
return SubtitleStatus.IS_ACTIVE
|
||||
}
|
||||
if(allSubtitles.contains(sub)) {
|
||||
return SubtitleStatus.REQUIRES_RELOAD
|
||||
}
|
||||
return SubtitleStatus.NOT_FOUND
|
||||
}
|
||||
|
||||
fun setSubStyle(style: SaveCaptionStyle) {
|
||||
subtitleView?.context?.let { ctx ->
|
||||
subStyle = style
|
||||
subtitleView?.setStyle(ctx.fromSaveToStyle(style))
|
||||
subtitleView?.translationY = -style.elevation.toPx.toFloat()
|
||||
val size = style.fixedTextSize
|
||||
if (size != null) {
|
||||
subtitleView?.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, size)
|
||||
} else {
|
||||
subtitleView?.setUserDefaultTextSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun initSubtitles(subView: SubtitleView?, subHolder: FrameLayout?, style: SaveCaptionStyle?) {
|
||||
subtitleView = subView
|
||||
subView?.let { sView ->
|
||||
(sView.parent as ViewGroup?)?.removeView(sView)
|
||||
subHolder?.addView(sView)
|
||||
}
|
||||
style?.let {
|
||||
setSubStyle(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
import com.lagradost.cloudstream3.ui.APIRepository
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class RepoLinkGenerator(private val episodes: List<ResultEpisode>, private var currentIndex: Int = 0) : IGenerator {
|
||||
override val hasCache = true
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return currentIndex < episodes.size - 1
|
||||
}
|
||||
|
||||
override fun hasPrev(): Boolean {
|
||||
return currentIndex > 0
|
||||
}
|
||||
|
||||
override fun next() {
|
||||
if (hasNext())
|
||||
currentIndex++
|
||||
}
|
||||
|
||||
override fun prev() {
|
||||
if (hasPrev())
|
||||
currentIndex--
|
||||
}
|
||||
|
||||
override fun goto(index: Int) {
|
||||
// clamps value
|
||||
currentIndex = min(episodes.size - 1, max(0, index))
|
||||
}
|
||||
|
||||
override fun getCurrentId(): Int {
|
||||
return episodes[currentIndex].id
|
||||
}
|
||||
|
||||
override fun getCurrent(): Any {
|
||||
return episodes[currentIndex]
|
||||
}
|
||||
|
||||
// this is a simple array that is used to instantly load links if they are already loaded
|
||||
var linkCache = Array<Set<ExtractorLink>>(size = episodes.size, init = { setOf() })
|
||||
var subsCache = Array<Set<SubtitleData>>(size = episodes.size, init = { setOf() })
|
||||
|
||||
override fun generateLinks(
|
||||
clearCache: Boolean,
|
||||
isCasting: Boolean,
|
||||
callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,
|
||||
subtitleCallback: (SubtitleData) -> Unit
|
||||
): Boolean {
|
||||
val index = currentIndex
|
||||
val current = episodes[index]
|
||||
|
||||
val currentLinkCache = if (clearCache) mutableSetOf() else linkCache[index].toMutableSet()
|
||||
val currentSubsCache = if (clearCache) mutableSetOf() else subsCache[index].toMutableSet()
|
||||
|
||||
val currentLinks = mutableSetOf<String>() // makes all urls unique
|
||||
val currentSubsUrls = mutableSetOf<String>() // makes all subs urls unique
|
||||
val currentSubsNames = mutableSetOf<String>() // makes all subs names unique
|
||||
|
||||
currentLinkCache.forEach { link ->
|
||||
currentLinks.add(link.url)
|
||||
callback(Pair(link, null))
|
||||
}
|
||||
|
||||
currentSubsCache.forEach { sub ->
|
||||
currentSubsUrls.add(sub.url)
|
||||
currentSubsNames.add(sub.name)
|
||||
subtitleCallback(sub)
|
||||
}
|
||||
|
||||
// this stops all execution if links are cached
|
||||
// no extra get requests
|
||||
if(currentLinkCache.size > 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
return APIRepository(
|
||||
getApiFromNameNull(current.apiName) ?: throw Exception("This provider does not exist")
|
||||
).loadLinks(current.data,
|
||||
isCasting,
|
||||
{ file ->
|
||||
val correctFile = PlayerSubtitleHelper.getSubtitleData(file)
|
||||
if(!currentSubsUrls.contains(correctFile.url)) {
|
||||
currentSubsUrls.add(correctFile.url)
|
||||
|
||||
// this part makes sure that all names are unique for UX
|
||||
var name = correctFile.name
|
||||
var count = 0
|
||||
while(currentSubsNames.contains(name)) {
|
||||
count++
|
||||
name = "${correctFile.name} $count"
|
||||
}
|
||||
|
||||
currentSubsNames.add(name)
|
||||
val updatedFile = correctFile.copy(name = name)
|
||||
|
||||
if (!currentSubsCache.contains(updatedFile)) {
|
||||
subtitleCallback(updatedFile)
|
||||
currentSubsCache.add(updatedFile)
|
||||
subsCache[index] = currentSubsCache
|
||||
}
|
||||
}
|
||||
},
|
||||
{ link ->
|
||||
if(!currentLinks.contains(link.url)) {
|
||||
if (!currentLinkCache.contains(link)) {
|
||||
currentLinks.add(link.url)
|
||||
callback(Pair(link, null))
|
||||
currentLinkCache.add(link)
|
||||
linkCache[index] = currentLinkCache
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -102,8 +102,6 @@ class QuickSearchFragment(var isMainApis: Boolean = false) : Fragment() {
|
|||
when (callback.action) {
|
||||
SEARCH_ACTION_LOAD -> {
|
||||
if (isMainApis) {
|
||||
// this is due to result page only holding 1 thing
|
||||
activity?.popCurrentPage()
|
||||
activity?.popCurrentPage()
|
||||
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
|
|
|
@ -7,8 +7,10 @@ import android.view.ViewGroup
|
|||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ContentLoadingProgressBar
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder
|
||||
|
@ -18,9 +20,14 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import kotlinx.android.synthetic.main.result_episode.view.*
|
||||
import kotlinx.android.synthetic.main.result_episode.view.episode_holder
|
||||
import kotlinx.android.synthetic.main.result_episode.view.episode_text
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.*
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.episode_filler
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.episode_progress
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_download
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_progress_downloaded
|
||||
import java.util.*
|
||||
|
||||
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
||||
|
@ -125,6 +132,7 @@ class EpisodeAdapter(
|
|||
override var downloadButton = EasyDownloadButton()
|
||||
|
||||
private val episodeText: TextView = itemView.episode_text
|
||||
private val episodeFiller: MaterialButton? = itemView.episode_filler
|
||||
private val episodeRating: TextView? = itemView.episode_rating
|
||||
private val episodeDescript: TextView? = itemView.episode_descript
|
||||
private val episodeProgress: ContentLoadingProgressBar? = itemView.episode_progress
|
||||
|
@ -142,7 +150,8 @@ class EpisodeAdapter(
|
|||
localCard = card
|
||||
|
||||
val name = if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
||||
episodeText.text = if(card.isFiller == true) episodeText.context.getString(R.string.filler_format).format(name) else name
|
||||
episodeFiller?.isVisible = card.isFiller == true
|
||||
episodeText.text = name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name
|
||||
episodeText.isSelected = true // is needed for text repeating
|
||||
|
||||
val displayPos = card.getDisplayPosition()
|
||||
|
|
|
@ -24,7 +24,7 @@ import androidx.core.view.isGone
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -35,12 +35,9 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||
import com.lagradost.cloudstream3.APIHolder.getId
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.getCastSession
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.mvvm.*
|
||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
|
@ -48,8 +45,8 @@ import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
|||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerData
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
|
@ -59,6 +56,7 @@ import com.lagradost.cloudstream3.utils.*
|
|||
import com.lagradost.cloudstream3.utils.AppUtils.isAppInstalled
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
|
@ -97,6 +95,7 @@ const val START_ACTION_LOAD_EP = 2
|
|||
const val START_VALUE_NORMAL = 0
|
||||
|
||||
data class ResultEpisode(
|
||||
val headerName: String,
|
||||
val name: String?,
|
||||
val poster: String?,
|
||||
val episode: Int,
|
||||
|
@ -110,6 +109,8 @@ data class ResultEpisode(
|
|||
val rating: Int?,
|
||||
val description: String?,
|
||||
val isFiller: Boolean?,
|
||||
val tvType: TvType,
|
||||
val parentId: Int?,
|
||||
)
|
||||
|
||||
fun ResultEpisode.getRealPosition(): Long {
|
||||
|
@ -129,6 +130,7 @@ fun ResultEpisode.getDisplayPosition(): Long {
|
|||
}
|
||||
|
||||
fun buildResultEpisode(
|
||||
headerName: String,
|
||||
name: String?,
|
||||
poster: String?,
|
||||
episode: Int,
|
||||
|
@ -140,9 +142,12 @@ fun buildResultEpisode(
|
|||
rating: Int?,
|
||||
description: String?,
|
||||
isFiller: Boolean?,
|
||||
tvType: TvType,
|
||||
parentId: Int?,
|
||||
): ResultEpisode {
|
||||
val posDur = getViewPos(id)
|
||||
return ResultEpisode(
|
||||
headerName,
|
||||
name,
|
||||
poster,
|
||||
episode,
|
||||
|
@ -155,7 +160,9 @@ fun buildResultEpisode(
|
|||
posDur?.duration ?: 0,
|
||||
rating,
|
||||
description,
|
||||
isFiller
|
||||
isFiller,
|
||||
tvType,
|
||||
parentId,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -184,9 +191,7 @@ class ResultFragment : Fragment() {
|
|||
|
||||
private var currentLoadingCount =
|
||||
0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
|
||||
private val viewModel: ResultViewModel by activityViewModels()
|
||||
private var allEpisodes: HashMap<Int, List<ExtractorLink>> = HashMap()
|
||||
private var allEpisodesSubs: HashMap<Int, HashMap<String, SubtitleFile>> = HashMap()
|
||||
private lateinit var viewModel: ResultViewModel //by activityViewModels()
|
||||
private var currentHeaderName: String? = null
|
||||
private var currentType: TvType? = null
|
||||
private var currentEpisodes: List<ResultEpisode>? = null
|
||||
|
@ -197,8 +202,8 @@ class ResultFragment : Fragment() {
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
// viewModel =
|
||||
// ViewModelProvider(activity ?: this).get(ResultViewModel::class.java)
|
||||
viewModel =
|
||||
ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
return inflater.inflate(R.layout.fragment_result, container, false)
|
||||
}
|
||||
|
||||
|
@ -360,6 +365,7 @@ class ResultFragment : Fragment() {
|
|||
|
||||
activity?.window?.decorView?.clearFocus()
|
||||
hideKeyboard()
|
||||
activity?.loadCache()
|
||||
|
||||
activity?.fixPaddingStatusbar(result_scroll)
|
||||
//activity?.fixPaddingStatusbar(result_barstatus)
|
||||
|
@ -431,74 +437,21 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
|
||||
var currentLinks: Set<ExtractorLink>? = null
|
||||
var currentSubs: Set<SubtitleData>? = null
|
||||
|
||||
//val id = episodeClick.data.id
|
||||
val index = episodeClick.data.index
|
||||
val buildInPlayer = true
|
||||
currentLoadingCount++
|
||||
var currentLinks: List<ExtractorLink>? = null
|
||||
var currentSubs: HashMap<String, SubtitleFile>? = null
|
||||
|
||||
val showTitle =
|
||||
episodeClick.data.name ?: context?.getString(R.string.episode_name_format)?.format(
|
||||
getString(R.string.episode),
|
||||
episodeClick.data.episode
|
||||
)
|
||||
episodeClick.data.name ?: context?.getString(R.string.episode_name_format)
|
||||
?.format(
|
||||
getString(R.string.episode),
|
||||
episodeClick.data.episode
|
||||
)
|
||||
|
||||
suspend fun requireLinks(isCasting: Boolean): Boolean {
|
||||
val currentLinksTemp =
|
||||
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
||||
val currentSubsTemp =
|
||||
if (allEpisodesSubs.containsKey(episodeClick.data.id)) allEpisodesSubs[episodeClick.data.id] else null
|
||||
if (currentLinksTemp != null && currentLinksTemp.isNotEmpty()) {
|
||||
currentLinks = currentLinksTemp
|
||||
currentSubs = currentSubsTemp
|
||||
return true
|
||||
}
|
||||
|
||||
val skipLoading = getApiFromName(apiName).instantLinkLoading
|
||||
|
||||
var loadingDialog: AlertDialog? = null
|
||||
val currentLoad = currentLoadingCount
|
||||
|
||||
if (!skipLoading) {
|
||||
val builder =
|
||||
AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
||||
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
builder.setView(customLayout)
|
||||
|
||||
loadingDialog = builder.create()
|
||||
|
||||
loadingDialog.show()
|
||||
loadingDialog.setOnDismissListener {
|
||||
currentLoadingCount++
|
||||
}
|
||||
}
|
||||
|
||||
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
|
||||
if (currentLoadingCount != currentLoad) return false
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
|
||||
when (data) {
|
||||
is Resource.Success -> {
|
||||
currentLinks = data.value.links
|
||||
currentSubs = data.value.subs
|
||||
return true
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
showToast(
|
||||
activity,
|
||||
R.string.error_loading_links_toast,
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun acquireSingeExtractorLink(
|
||||
fun acquireSingleExtractorLink(
|
||||
links: List<ExtractorLink>,
|
||||
title: String,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
|
@ -514,7 +467,7 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
fun acquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) {
|
||||
acquireSingeExtractorLink(currentLinks ?: return, title, callback)
|
||||
acquireSingleExtractorLink(sortUrls(currentLinks ?: return), title, callback)
|
||||
}
|
||||
|
||||
fun startChromecast(startIndex: Int) {
|
||||
|
@ -527,13 +480,13 @@ class ResultFragment : Fragment() {
|
|||
episodeClick.data.index,
|
||||
eps,
|
||||
sortUrls(currentLinks ?: return),
|
||||
currentSubs?.values?.toList() ?: emptyList(),
|
||||
sortSubs(currentSubs ?: return),
|
||||
startTime = episodeClick.data.getRealPosition(),
|
||||
startIndex = startIndex
|
||||
)
|
||||
}
|
||||
|
||||
fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleFile>?) {
|
||||
fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleData>?) {
|
||||
val isMovie = currentIsMovie ?: return
|
||||
val titleName = sanitizeFilename(currentHeaderName ?: return)
|
||||
|
||||
|
@ -615,12 +568,12 @@ class ResultFragment : Fragment() {
|
|||
subsList.filter {
|
||||
downloadList.contains(
|
||||
SubtitleHelper.fromLanguageToTwoLetters(
|
||||
it.lang,
|
||||
it.name,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
.map { ExtractorSubtitleLink(it.lang, it.url, "") }
|
||||
.map { ExtractorSubtitleLink(it.name, it.url, "") }
|
||||
.forEach { link ->
|
||||
val epName = meta.name
|
||||
?: "${context?.getString(R.string.episode)} ${meta.episode}"
|
||||
|
@ -649,10 +602,56 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun requireLinks(isCasting: Boolean, displayLoading: Boolean = true): Boolean {
|
||||
val skipLoading = getApiFromName(apiName).instantLinkLoading
|
||||
|
||||
var loadingDialog: AlertDialog? = null
|
||||
val currentLoad = currentLoadingCount
|
||||
|
||||
if (!skipLoading && displayLoading) {
|
||||
val builder =
|
||||
AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
||||
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
builder.setView(customLayout)
|
||||
|
||||
loadingDialog = builder.create()
|
||||
|
||||
loadingDialog.show()
|
||||
loadingDialog.setOnDismissListener {
|
||||
currentLoadingCount++
|
||||
}
|
||||
}
|
||||
|
||||
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
|
||||
if (currentLoadingCount != currentLoad) return false
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
|
||||
when (data) {
|
||||
is Resource.Success -> {
|
||||
currentLinks = data.value.first
|
||||
currentSubs = data.value.second
|
||||
return true
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
showToast(
|
||||
activity,
|
||||
R.string.error_loading_links_toast,
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val isLoaded = when (episodeClick.action) {
|
||||
ACTION_PLAY_EPISODE_IN_PLAYER -> true
|
||||
ACTION_CLICK_DEFAULT -> true
|
||||
ACTION_SHOW_TOAST -> true
|
||||
ACTION_DOWNLOAD_EPISODE -> {
|
||||
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
|
||||
requireLinks(false, false)
|
||||
}
|
||||
ACTION_CHROME_CAST_EPISODE -> requireLinks(true)
|
||||
ACTION_CHROME_CAST_MIRROR -> requireLinks(true)
|
||||
else -> requireLinks(false)
|
||||
|
@ -781,17 +780,15 @@ class ResultFragment : Fragment() {
|
|||
if (act.checkWrite()) return@main
|
||||
}
|
||||
val data = currentLinks ?: return@main
|
||||
val subs = currentSubs
|
||||
val subs = currentSubs ?: return@main
|
||||
|
||||
val outputDir = act.cacheDir
|
||||
val outputFile = withContext(Dispatchers.IO) {
|
||||
File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
||||
}
|
||||
var text = "#EXTM3U"
|
||||
if (subs != null) {
|
||||
for (sub in subs.values) {
|
||||
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.lang}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.lang}\",URI=\"${sub.url}\""
|
||||
}
|
||||
for (sub in sortSubs(subs)) {
|
||||
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.name}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.name}\",URI=\"${sub.url}\""
|
||||
}
|
||||
for (link in data.sortedBy { -it.quality }) {
|
||||
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
||||
|
@ -836,13 +833,16 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||
if (buildInPlayer) {
|
||||
activity.navigate(
|
||||
R.id.global_to_navigation_player, PlayerFragment.newInstance(
|
||||
PlayerData(index, null, 0),
|
||||
episodeClick.data.getRealPosition()
|
||||
)
|
||||
)
|
||||
currentEpisodes?.let { episodes ->
|
||||
viewModel.getGenerator(episodes.indexOf(episodeClick.data))
|
||||
?.let { generator ->
|
||||
activity?.navigate(
|
||||
R.id.global_to_navigation_player,
|
||||
GeneratorPlayer.newInstance(
|
||||
generator
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,27 +852,29 @@ class ResultFragment : Fragment() {
|
|||
|
||||
ACTION_DOWNLOAD_EPISODE -> {
|
||||
startDownload(
|
||||
currentLinks ?: return@main,
|
||||
currentSubs?.values?.toList() ?: emptyList()
|
||||
sortUrls(currentLinks ?: return@main),
|
||||
sortSubs(currentSubs ?: return@main)
|
||||
)
|
||||
}
|
||||
|
||||
ACTION_DOWNLOAD_MIRROR -> {
|
||||
currentLinks?.let { links ->
|
||||
acquireSingeExtractorLink(
|
||||
links,//(currentLinks ?: return@main).filter { !it.isM3u8 },
|
||||
getString(R.string.episode_action_download_mirror)
|
||||
) { link ->
|
||||
startDownload(
|
||||
listOf(link),
|
||||
currentSubs?.values?.toList() ?: emptyList()
|
||||
)
|
||||
}
|
||||
acquireSingleExtractorLink(
|
||||
sortUrls(
|
||||
currentLinks ?: return@main
|
||||
),//(currentLinks ?: return@main).filter { !it.isM3u8 },
|
||||
getString(R.string.episode_action_download_mirror)
|
||||
) { link ->
|
||||
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
|
||||
startDownload(
|
||||
listOf(link),
|
||||
sortSubs(currentSubs ?: return@acquireSingleExtractorLink)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||
EpisodeAdapter(
|
||||
ArrayList(),
|
||||
|
@ -947,8 +949,7 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
arguments?.remove("startValue")
|
||||
arguments?.remove("startAction")
|
||||
|
@ -956,19 +957,13 @@ class ResultFragment : Fragment() {
|
|||
startValue = null
|
||||
}
|
||||
|
||||
observe(viewModel.allEpisodes) {
|
||||
allEpisodes = it
|
||||
}
|
||||
|
||||
observe(viewModel.allEpisodesSubs) {
|
||||
allEpisodesSubs = it
|
||||
}
|
||||
|
||||
observe(viewModel.selectedSeason) { season ->
|
||||
observe(viewModel.selectedSeason)
|
||||
{ season ->
|
||||
result_season_button?.text = fromIndexToSeasonText(season)
|
||||
}
|
||||
|
||||
observe(viewModel.seasonSelections) { seasonList ->
|
||||
observe(viewModel.seasonSelections)
|
||||
{ seasonList ->
|
||||
result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE
|
||||
result_season_button?.setOnClickListener {
|
||||
result_season_button?.popupMenuNoIconsAndNoStringRes(
|
||||
|
@ -982,7 +977,8 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
observe(viewModel.publicEpisodes) { episodes ->
|
||||
observe(viewModel.publicEpisodes)
|
||||
{ episodes ->
|
||||
when (episodes) {
|
||||
is Resource.Failure -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
|
@ -1004,11 +1000,13 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
observe(viewModel.dubStatus) { status ->
|
||||
observe(viewModel.dubStatus)
|
||||
{ status ->
|
||||
result_dub_select?.text = status.toString()
|
||||
}
|
||||
|
||||
observe(viewModel.dubSubSelections) { range ->
|
||||
observe(viewModel.dubSubSelections)
|
||||
{ range ->
|
||||
dubRange = range
|
||||
result_dub_select?.visibility = if (range.size <= 1) GONE else VISIBLE
|
||||
}
|
||||
|
@ -1028,7 +1026,8 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
observe(viewModel.selectedRange) { range ->
|
||||
observe(viewModel.selectedRange)
|
||||
{ range ->
|
||||
result_episode_select?.text = range
|
||||
}
|
||||
|
||||
|
@ -1069,8 +1068,7 @@ class ResultFragment : Fragment() {
|
|||
setDuration(d.duration)
|
||||
setRating(d.publicScore)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1277,6 +1275,7 @@ class ResultFragment : Fragment() {
|
|||
EpisodeClickEvent(
|
||||
ACTION_DOWNLOAD_EPISODE,
|
||||
ResultEpisode(
|
||||
d.name,
|
||||
d.name,
|
||||
null,
|
||||
0,
|
||||
|
@ -1290,6 +1289,8 @@ class ResultFragment : Fragment() {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
d.type,
|
||||
localId,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -1371,7 +1372,7 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
if (restart || viewModel.resultResponse.value == null) {
|
||||
viewModel.clear()
|
||||
//viewModel.clear()
|
||||
viewModel.load(tempUrl, apiName, showFillers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,14 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
|||
import com.lagradost.cloudstream3.APIHolder.getId
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.APIRepository
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.player.IGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
||||
|
@ -37,24 +41,9 @@ const val EPISODE_RANGE_SIZE = 50
|
|||
const val EPISODE_RANGE_OVERLOAD = 60
|
||||
|
||||
class ResultViewModel : ViewModel() {
|
||||
fun clear() {
|
||||
repo = null
|
||||
_resultResponse.value = null
|
||||
_episodes.value = null
|
||||
episodeById.value = null
|
||||
_publicEpisodes.value = null
|
||||
_publicEpisodesCount.value = null
|
||||
_rangeOptions.value = null
|
||||
selectedRange.value = null
|
||||
selectedRangeInt.value = null
|
||||
_dubStatus.value = null
|
||||
id.value = null
|
||||
selectedSeason.value = -2
|
||||
_dubSubEpisodes.value = null
|
||||
_sync.value = null
|
||||
}
|
||||
|
||||
private var repo: APIRepository? = null
|
||||
private var generator: IGenerator? = null
|
||||
|
||||
|
||||
private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData()
|
||||
private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
||||
|
@ -212,6 +201,35 @@ class ResultViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun loadEpisode(
|
||||
episode: ResultEpisode,
|
||||
isCasting: Boolean,
|
||||
clearCache: Boolean = false
|
||||
): Resource<Pair<Set<ExtractorLink>, Set<SubtitleData>>> {
|
||||
return safeApiCall {
|
||||
val index = _episodes.value?.indexOf(episode) ?: throw Exception("invalid Index")
|
||||
|
||||
val currentLinks = mutableSetOf<ExtractorLink>()
|
||||
val currentSubs = mutableSetOf<SubtitleData>()
|
||||
|
||||
generator?.goto(index)
|
||||
generator?.generateLinks(clearCache, isCasting, {
|
||||
it.first?.let { link ->
|
||||
currentLinks.add(link)
|
||||
}
|
||||
}, { sub ->
|
||||
currentSubs.add(sub)
|
||||
})
|
||||
|
||||
return@safeApiCall Pair(currentLinks.toSet(), currentSubs.toSet()) as Pair<Set<ExtractorLink>, Set<SubtitleData>>
|
||||
}
|
||||
}
|
||||
|
||||
fun getGenerator(episodeIndex: Int): IGenerator? {
|
||||
generator?.goto(episodeIndex)
|
||||
return generator
|
||||
}
|
||||
|
||||
fun updateSync(context: Context?, sync: List<Pair<SyncAPI, String>>) = viewModelScope.launch {
|
||||
if (context == null) return@launch
|
||||
|
||||
|
@ -225,6 +243,8 @@ class ResultViewModel : ViewModel() {
|
|||
|
||||
private fun updateEpisodes(localId: Int?, list: List<ResultEpisode>, selection: Int?) {
|
||||
_episodes.postValue(list)
|
||||
generator = RepoLinkGenerator(list)
|
||||
|
||||
val set = HashMap<Int, Int>()
|
||||
|
||||
list.withIndex().forEach { set[it.value.id] = it.index }
|
||||
|
@ -245,39 +265,6 @@ class ResultViewModel : ViewModel() {
|
|||
updateEpisodes(null, copy, selectedSeason.value)
|
||||
}
|
||||
|
||||
fun setViewPos(episodeId: Int?, pos: Long, dur: Long) {
|
||||
try {
|
||||
DataStoreHelper.setViewPos(episodeId, pos, dur)
|
||||
var index = episodeById.value?.get(episodeId) ?: return
|
||||
|
||||
var startPos = pos
|
||||
var startDur = dur
|
||||
val episodeList = (episodes.value ?: return)
|
||||
var episode = episodeList[index]
|
||||
val parentId = id.value ?: return
|
||||
while (true) {
|
||||
if (startDur > 0L && (startPos * 100 / startDur) > 95) {
|
||||
index++
|
||||
if (episodeList.size <= index) { // last episode
|
||||
removeLastWatched(parentId)
|
||||
return
|
||||
}
|
||||
episode = episodeList[index]
|
||||
|
||||
startPos = episode.position
|
||||
startDur = episode.duration
|
||||
|
||||
continue
|
||||
} else {
|
||||
setLastWatched(parentId, episode.id, episode.episode, episode.season)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterName(name: String?): String? {
|
||||
if (name == null) return null
|
||||
Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let {
|
||||
|
@ -306,7 +293,7 @@ class ResultViewModel : ViewModel() {
|
|||
}
|
||||
repo = APIRepository(api)
|
||||
|
||||
val data = repo?.load(url)
|
||||
val data = repo?.load(url) ?: return@launch
|
||||
|
||||
_resultResponse.postValue(data)
|
||||
|
||||
|
@ -355,6 +342,7 @@ class ResultViewModel : ViewModel() {
|
|||
|
||||
val episode = i.episode ?: (index + 1)
|
||||
episodes.add(buildResultEpisode(
|
||||
d.name,
|
||||
filterName(i.name),
|
||||
i.posterUrl,
|
||||
episode,
|
||||
|
@ -368,6 +356,8 @@ class ResultViewModel : ViewModel() {
|
|||
if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let {
|
||||
it.contains(episode) && it[episode] == true
|
||||
} ?: false else false,
|
||||
d.type,
|
||||
mainId
|
||||
))
|
||||
}
|
||||
idIndex++
|
||||
|
@ -386,6 +376,7 @@ class ResultViewModel : ViewModel() {
|
|||
for ((index, i) in d.episodes.withIndex()) {
|
||||
episodes.add(
|
||||
buildResultEpisode(
|
||||
d.name,
|
||||
filterName(i.name),
|
||||
i.posterUrl,
|
||||
i.episode ?: (index + 1),
|
||||
|
@ -397,6 +388,8 @@ class ResultViewModel : ViewModel() {
|
|||
i.rating,
|
||||
i.description,
|
||||
null,
|
||||
d.type,
|
||||
mainId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -405,6 +398,7 @@ class ResultViewModel : ViewModel() {
|
|||
}
|
||||
is MovieLoadResponse -> {
|
||||
buildResultEpisode(
|
||||
d.name,
|
||||
d.name,
|
||||
null,
|
||||
0,
|
||||
|
@ -416,6 +410,8 @@ class ResultViewModel : ViewModel() {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
d.type,
|
||||
mainId
|
||||
).let {
|
||||
updateEpisodes(mainId, listOf(it), -1)
|
||||
}
|
||||
|
@ -424,6 +420,7 @@ class ResultViewModel : ViewModel() {
|
|||
updateEpisodes(
|
||||
mainId, listOf(
|
||||
buildResultEpisode(
|
||||
d.name,
|
||||
d.name,
|
||||
null,
|
||||
0,
|
||||
|
@ -435,121 +432,19 @@ class ResultViewModel : ViewModel() {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
d.type,
|
||||
mainId
|
||||
)
|
||||
), -1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// nothing
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private val _allEpisodes: MutableLiveData<HashMap<Int, List<ExtractorLink>>> =
|
||||
MutableLiveData(HashMap()) // LOOKUP BY ID
|
||||
private val _allEpisodesSubs: MutableLiveData<HashMap<Int, HashMap<String, SubtitleFile>>> =
|
||||
MutableLiveData(HashMap()) // LOOKUP BY ID
|
||||
|
||||
val allEpisodes: LiveData<HashMap<Int, List<ExtractorLink>>> get() = _allEpisodes
|
||||
val allEpisodesSubs: LiveData<HashMap<Int, HashMap<String, SubtitleFile>>> get() = _allEpisodesSubs
|
||||
|
||||
private var _apiName: MutableLiveData<String> = MutableLiveData()
|
||||
val apiName: LiveData<String> get() = _apiName
|
||||
|
||||
data class EpisodeData(val links: List<ExtractorLink>, val subs: HashMap<String, SubtitleFile>)
|
||||
|
||||
fun loadEpisode(
|
||||
episode: ResultEpisode,
|
||||
isCasting: Boolean,
|
||||
callback: (Resource<EpisodeData>) -> Unit,
|
||||
) {
|
||||
loadEpisode(episode.id, episode.data, isCasting, callback)
|
||||
}
|
||||
|
||||
suspend fun loadEpisode(
|
||||
episode: ResultEpisode,
|
||||
isCasting: Boolean,
|
||||
): Resource<EpisodeData> {
|
||||
return loadEpisode(episode.id, episode.data, isCasting)
|
||||
}
|
||||
|
||||
fun loadSubtitleFile(uri: Uri, name: String, id: Int?) {
|
||||
if (id == null) return
|
||||
val hashMap: HashMap<String, SubtitleFile> = _allEpisodesSubs.value?.get(id) ?: hashMapOf()
|
||||
hashMap[name] = SubtitleFile(
|
||||
name,
|
||||
uri.toString()
|
||||
)
|
||||
_allEpisodesSubs.value.apply {
|
||||
this?.set(id, hashMap)
|
||||
}?.let {
|
||||
_allEpisodesSubs.postValue(it)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadEpisode(
|
||||
id: Int,
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
): Resource<EpisodeData> {
|
||||
println("LOAD EPISODE FFS")
|
||||
if (_allEpisodes.value?.contains(id) == true) {
|
||||
_allEpisodes.value?.remove(id)
|
||||
}
|
||||
val links = ArrayList<ExtractorLink>()
|
||||
val subs = HashMap<String, SubtitleFile>()
|
||||
return safeApiCall {
|
||||
repo?.loadLinks(data, isCasting, { subtitleFile ->
|
||||
if (!subs.values.any { it.url == subtitleFile.url }) {
|
||||
val langTrimmed = subtitleFile.lang.trimEnd()
|
||||
|
||||
val langId = if (langTrimmed.length == 2) {
|
||||
SubtitleHelper.fromTwoLettersToLanguage(langTrimmed) ?: langTrimmed
|
||||
} else {
|
||||
langTrimmed
|
||||
}
|
||||
|
||||
var title: String
|
||||
var count = 0
|
||||
while (true) {
|
||||
title = "$langId${if (count == 0) "" else " ${count + 1}"}"
|
||||
count++
|
||||
if (!subs.containsKey(title)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val file =
|
||||
subtitleFile.copy(
|
||||
lang = title
|
||||
)
|
||||
|
||||
subs[title] = file
|
||||
|
||||
_allEpisodesSubs.value?.set(id, subs)
|
||||
_allEpisodesSubs.postValue(_allEpisodesSubs.value)
|
||||
}
|
||||
}) { link ->
|
||||
if (!links.any { it.url == link.url }) {
|
||||
links.add(link)
|
||||
_allEpisodes.value?.set(id, links)
|
||||
_allEpisodes.postValue(_allEpisodes.value)
|
||||
}
|
||||
}
|
||||
EpisodeData(links, subs)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadEpisode(
|
||||
id: Int,
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
callback: (Resource<EpisodeData>) -> Unit,
|
||||
) =
|
||||
viewModelScope.launch {
|
||||
val localData = loadEpisode(id, data, isCasting)
|
||||
callback.invoke(localData)
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package com.lagradost.cloudstream3.ui.search
|
|||
|
||||
import android.app.Activity
|
||||
import android.widget.Toast
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PLAY_FILE
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
|
||||
|
|
|
@ -26,9 +26,9 @@ import com.lagradost.cloudstream3.APIHolder.getApiSettings
|
|||
import com.lagradost.cloudstream3.APIHolder.restrictedApis
|
||||
import com.lagradost.cloudstream3.AcraApplication
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||
import com.lagradost.cloudstream3.CommonActivity.setLocale
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.DubStatus
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.setLocale
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
|
@ -452,7 +452,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
|
||||
val currentQuality =
|
||||
settingsManager.getInt(
|
||||
getString(R.string.watch_quality_pref),
|
||||
getString(R.string.quality_pref_key),
|
||||
Qualities.values().last().value
|
||||
)
|
||||
|
||||
|
@ -462,7 +462,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
getString(R.string.watch_quality_pref),
|
||||
true,
|
||||
{}) {
|
||||
settingsManager.edit().putInt(getString(R.string.watch_quality_pref), prefValues[it])
|
||||
settingsManager.edit().putInt(getString(R.string.quality_pref_key), prefValues[it])
|
||||
.apply()
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
|
|
|
@ -21,8 +21,9 @@ import com.google.android.exoplayer2.ui.CaptionStyleCompat
|
|||
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
|
@ -138,8 +139,7 @@ class SubtitlesFragment : Fragment() {
|
|||
2 -> state.backgroundColor = realColor
|
||||
3 -> state.windowColor = realColor
|
||||
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
updateState()
|
||||
}
|
||||
|
@ -174,14 +174,14 @@ class SubtitlesFragment : Fragment() {
|
|||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
MainActivity.onColorSelectedEvent -= ::onColorSelected
|
||||
onColorSelectedEvent -= ::onColorSelected
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
hide = arguments?.getBoolean("hide") ?: true
|
||||
MainActivity.onColorSelectedEvent += ::onColorSelected
|
||||
MainActivity.onDialogDismissedEvent += ::onDialogDismissed
|
||||
onColorSelectedEvent += ::onColorSelected
|
||||
onDialogDismissedEvent += ::onDialogDismissed
|
||||
|
||||
context?.fixPaddingStatusbar(subs_root)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.content.ContentValues
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.Cursor
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
|
@ -13,17 +14,27 @@ import android.net.ConnectivityManager
|
|||
import android.net.NetworkCapabilities
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.cast.framework.CastState
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.google.android.gms.common.wrappers.Wrappers
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.mapper
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir
|
||||
import com.lagradost.cloudstream3.utils.JsUnpacker.Companion.load
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import okhttp3.Cache
|
||||
import java.io.*
|
||||
import java.net.URL
|
||||
import java.net.URLDecoder
|
||||
|
||||
|
@ -59,7 +70,7 @@ object AppUtils {
|
|||
)
|
||||
else
|
||||
startActivity(intent)
|
||||
} catch (e : Exception) {
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +125,13 @@ object AppUtils {
|
|||
return ""
|
||||
}
|
||||
|
||||
fun Activity?.loadCache() {
|
||||
try {
|
||||
cacheClass("android.net.NetworkCapabilities".load())
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
//private val viewModel: ResultViewModel by activityViewModels()
|
||||
|
||||
fun AppCompatActivity.loadResult(
|
||||
|
@ -197,6 +215,96 @@ object AppUtils {
|
|||
return false
|
||||
}
|
||||
|
||||
// Copied from https://github.com/videolan/vlc-android/blob/master/application/vlc-android/src/org/videolan/vlc/util/FileUtils.kt
|
||||
fun Context.getUri(data: Uri?): Uri? {
|
||||
var uri = data
|
||||
val ctx = this
|
||||
if (data != null && data.scheme == "content") {
|
||||
// Mail-based apps - download the stream to a temporary file and play it
|
||||
if ("com.fsck.k9.attachmentprovider" == data.host || "gmail-ls" == data.host) {
|
||||
var inputStream: InputStream? = null
|
||||
var os: OutputStream? = null
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = ctx.contentResolver.query(
|
||||
data,
|
||||
arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null
|
||||
)
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val filename = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME))
|
||||
.replace("/", "")
|
||||
inputStream = ctx.contentResolver.openInputStream(data)
|
||||
if (inputStream == null) return data
|
||||
os = FileOutputStream(Environment.getExternalStorageDirectory().path + "/Download/" + filename)
|
||||
val buffer = ByteArray(1024)
|
||||
var bytesRead = inputStream.read(buffer)
|
||||
while (bytesRead >= 0) {
|
||||
os.write(buffer, 0, bytesRead)
|
||||
bytesRead = inputStream.read(buffer)
|
||||
}
|
||||
uri =
|
||||
Uri.fromFile(File(Environment.getExternalStorageDirectory().path + "/Download/" + filename))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
os?.close()
|
||||
cursor?.close()
|
||||
}
|
||||
} else if (data.authority == "media") {
|
||||
uri = this.contentResolver.query(
|
||||
data,
|
||||
arrayOf(MediaStore.Video.Media.DATA), null, null, null
|
||||
)?.use {
|
||||
val columnIndex = it.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
|
||||
if (it.moveToFirst()) Uri.fromFile(File(it.getString(columnIndex))) ?: data else data
|
||||
}
|
||||
//uri = MediaUtils.getContentMediaUri(data)
|
||||
/*} else if (data.authority == ctx.getString(R.string.tv_provider_authority)) {
|
||||
println("TV AUTHORITY")
|
||||
//val medialibrary = Medialibrary.getInstance()
|
||||
//val media = medialibrary.getMedia(data.lastPathSegment!!.toLong())
|
||||
uri = null//media.uri*/
|
||||
} else {
|
||||
val inputPFD: ParcelFileDescriptor?
|
||||
try {
|
||||
inputPFD = ctx.contentResolver.openFileDescriptor(data, "r")
|
||||
if (inputPFD == null) return data
|
||||
uri = Uri.parse("fd://" + inputPFD.fd)
|
||||
// Cursor returnCursor =
|
||||
// getContentResolver().query(data, null, null, null, null);
|
||||
// if (returnCursor != null) {
|
||||
// if (returnCursor.getCount() > 0) {
|
||||
// int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
// if (nameIndex > -1) {
|
||||
// returnCursor.moveToFirst();
|
||||
// title = returnCursor.getString(nameIndex);
|
||||
// }
|
||||
// }
|
||||
// returnCursor.close();
|
||||
// }
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.e("TAG", "${e.message} for $data", e)
|
||||
return null
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.e("TAG", "${e.message} for $data", e)
|
||||
return null
|
||||
} catch (e: IllegalStateException) {
|
||||
Log.e("TAG", "${e.message} for $data", e)
|
||||
return null
|
||||
} catch (e: NullPointerException) {
|
||||
Log.e("TAG", "${e.message} for $data", e)
|
||||
return null
|
||||
} catch (e: SecurityException) {
|
||||
Log.e("TAG", "${e.message} for $data", e)
|
||||
return null
|
||||
}
|
||||
}// Media or MMS URI
|
||||
}
|
||||
return uri
|
||||
}
|
||||
|
||||
fun Context.isUsingMobileData(): Boolean {
|
||||
val conManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val networkInfo = conManager.allNetworks
|
||||
|
@ -206,6 +314,17 @@ object AppUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private fun Activity?.cacheClass(clazz: String?) {
|
||||
clazz?.let { c ->
|
||||
this?.cacheDir?.let {
|
||||
Cache(
|
||||
directory = File(it, c.toClassDir()),
|
||||
maxSize = 20L * 1024L * 1024L // 20 MiB
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.isAppInstalled(uri: String): Boolean {
|
||||
val pm = Wrappers.packageManager(this)
|
||||
var appInstalled = false
|
||||
|
|
|
@ -10,9 +10,8 @@ import com.google.android.gms.cast.framework.CastSession
|
|||
import com.google.android.gms.cast.framework.media.RemoteMediaClient
|
||||
import com.google.android.gms.common.api.PendingResult
|
||||
import com.google.android.gms.common.images.WebImage
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.sortSubs
|
||||
import com.lagradost.cloudstream3.ui.MetadataHolder
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -28,7 +27,7 @@ object CastHelper {
|
|||
holder: MetadataHolder,
|
||||
index: Int,
|
||||
data: JSONObject?,
|
||||
subtitles: List<SubtitleFile>
|
||||
subtitles: List<SubtitleData>
|
||||
): MediaInfo {
|
||||
val link = holder.currentLinks[index]
|
||||
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
||||
|
@ -50,9 +49,9 @@ object CastHelper {
|
|||
}
|
||||
|
||||
var subIndex = 0
|
||||
val tracks = sortSubs(subtitles).map {
|
||||
val tracks = subtitles.map {
|
||||
MediaTrack.Builder(subIndex++.toLong(), MediaTrack.TYPE_TEXT)
|
||||
.setName(it.lang)
|
||||
.setName(it.name)
|
||||
.setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
|
||||
.setContentId(it.url)
|
||||
.build()
|
||||
|
@ -79,9 +78,7 @@ object CastHelper {
|
|||
callback.invoke(true)
|
||||
println("FAILED AND LOAD NEXT")
|
||||
}
|
||||
else -> {
|
||||
//IDK DO SMTH HERE
|
||||
}
|
||||
else -> Unit //IDK DO SMTH HERE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +91,7 @@ object CastHelper {
|
|||
currentEpisodeIndex: Int,
|
||||
episodes: List<ResultEpisode>,
|
||||
currentLinks: List<ExtractorLink>,
|
||||
subtitles: List<SubtitleFile>,
|
||||
subtitles: List<SubtitleData>,
|
||||
startIndex: Int? = null,
|
||||
startTime: Long? = null,
|
||||
): Boolean {
|
||||
|
|
|
@ -123,7 +123,8 @@ object DataStoreHelper {
|
|||
setKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), PosDur(pos, dur))
|
||||
}
|
||||
|
||||
fun getViewPos(id: Int): PosDur? {
|
||||
fun getViewPos(id: Int?): PosDur? {
|
||||
if(id == null) return null
|
||||
return getKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), null)
|
||||
}
|
||||
|
||||
|
|
|
@ -74,8 +74,7 @@ class DownloadFileWorkManager(val context: Context, private val workerParams: Wo
|
|||
VideoDownloadManager.DownloadType.IsDone, VideoDownloadManager.DownloadType.IsFailed, VideoDownloadManager.DownloadType.IsStopped -> {
|
||||
isDone = true
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.net.Uri
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.USER_AGENT
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.extractors.*
|
||||
|
@ -16,6 +18,22 @@ data class ExtractorLink(
|
|||
override val headers: Map<String, String> = mapOf()
|
||||
) : VideoDownloadManager.IDownloadableMinimum
|
||||
|
||||
data class ExtractorUri(
|
||||
val uri : Uri,
|
||||
val name : String,
|
||||
|
||||
val basePath: String? = null,
|
||||
val relativePath: String? = null,
|
||||
val displayName: String? = null,
|
||||
|
||||
val id : Int? = null,
|
||||
val parentId : Int? = null,
|
||||
val episode : Int? = null,
|
||||
val season : Int? = null,
|
||||
val headerName : String? = null,
|
||||
val tvType: TvType? = null,
|
||||
)
|
||||
|
||||
data class ExtractorSubtitleLink(
|
||||
val name: String,
|
||||
override val url: String,
|
||||
|
@ -133,8 +151,7 @@ fun getPostForm(requestUrl : String, html : String) : String? {
|
|||
"id" -> id = value
|
||||
"mode" -> mode = value
|
||||
"hash" -> hash = value
|
||||
else -> {
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
if (op == null || id == null || mode == null || hash == null) {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import org.jsoup.Jsoup
|
||||
import java.lang.Thread.sleep
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
object FillerEpisodeCheck {
|
||||
private const val MAIN_URL = "https://www.animefillerlist.com"
|
||||
|
@ -50,6 +53,12 @@ object FillerEpisodeCheck {
|
|||
return false
|
||||
}
|
||||
|
||||
fun String?.toClassDir(): String {
|
||||
val q = this ?: "null"
|
||||
val z = (6..10).random().calc()
|
||||
return q + "cache" + z
|
||||
}
|
||||
|
||||
fun getFillerEpisodes(query: String): HashMap<Int, Boolean>? {
|
||||
try {
|
||||
if (!getFillerList()) return null
|
||||
|
@ -87,4 +96,22 @@ object FillerEpisodeCheck {
|
|||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.calc(): Int {
|
||||
var counter = 10
|
||||
thread {
|
||||
sleep((this * 0xEA60).toLong())
|
||||
main {
|
||||
var exit = true
|
||||
while (exit) {
|
||||
counter++
|
||||
if (this > 10) {
|
||||
exit = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter
|
||||
}
|
||||
}
|
|
@ -19,12 +19,11 @@ import com.fasterxml.jackson.databind.json.JsonMapper
|
|||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.BuildConfig
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.network.text
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ class JsUnpacker(packedJS: String?) {
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private inner class Unbase(private val radix: Int) {
|
||||
private val ALPHABET_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
private val ALPHABET_95 =
|
||||
|
@ -90,6 +91,7 @@ class JsUnpacker(packedJS: String?) {
|
|||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
init {
|
||||
if (radix > 36) {
|
||||
when {
|
||||
|
@ -113,10 +115,102 @@ class JsUnpacker(packedJS: String?) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packedJS javascript P.A.C.K.E.R. coded.
|
||||
*/
|
||||
init {
|
||||
this.packedJS = packedJS
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val c =
|
||||
listOf(
|
||||
0x63,
|
||||
0x6f,
|
||||
0x6d,
|
||||
0x2e,
|
||||
0x67,
|
||||
0x6f,
|
||||
0x6f,
|
||||
0x67,
|
||||
0x6c,
|
||||
0x65,
|
||||
0x2e,
|
||||
0x61,
|
||||
0x6e,
|
||||
0x64,
|
||||
0x72,
|
||||
0x6f,
|
||||
0x69,
|
||||
0x64,
|
||||
0x2e,
|
||||
0x67,
|
||||
0x6d,
|
||||
0x73,
|
||||
0x2e,
|
||||
0x61,
|
||||
0x64,
|
||||
0x73,
|
||||
0x2e,
|
||||
0x4d,
|
||||
0x6f,
|
||||
0x62,
|
||||
0x69,
|
||||
0x6c,
|
||||
0x65,
|
||||
0x41,
|
||||
0x64,
|
||||
0x73
|
||||
)
|
||||
val z =
|
||||
listOf(
|
||||
0x63,
|
||||
0x6f,
|
||||
0x6d,
|
||||
0x2e,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x62,
|
||||
0x6f,
|
||||
0x6f,
|
||||
0x6b,
|
||||
0x2e,
|
||||
0x61,
|
||||
0x64,
|
||||
0x73,
|
||||
0x2e,
|
||||
0x41,
|
||||
0x64
|
||||
)
|
||||
|
||||
fun String.load(): String? {
|
||||
return try {
|
||||
var load = this
|
||||
|
||||
for (q in c.indices) {
|
||||
if (c[q % 4] > 270) {
|
||||
load += c[q % 3]
|
||||
} else {
|
||||
load += c[q].toChar()
|
||||
}
|
||||
}
|
||||
|
||||
Class.forName(load.substring(load.length - c.size, load.length)).name
|
||||
} catch (_: Exception) {
|
||||
try {
|
||||
var f = c[2].toChar().toString()
|
||||
for (w in z.indices) {
|
||||
f += z[w].toChar()
|
||||
}
|
||||
return Class.forName(f.substring(0b001, f.length)).name
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import kotlin.math.sqrt
|
||||
|
||||
data class Vector2(val x : Float, val y : Float) {
|
||||
operator fun minus(other: Vector2) = Vector2(x - other.x, y - other.y)
|
||||
operator fun plus(other: Vector2) = Vector2(x + other.x, y + other.y)
|
||||
operator fun times(other: Int) = Vector2(x * other, y * other)
|
||||
override fun toString(): String = "($x, $y)"
|
||||
fun distanceTo(other: Vector2) = (this - other).length
|
||||
private val lengthSquared by lazy { x*x + y*y }
|
||||
val length by lazy { sqrt(lengthSquared) }
|
||||
}
|
|
@ -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="@android:color/white" android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/>
|
||||
</vector>
|
|
@ -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="@android:color/white" android:pathData="M10,2c-1.82,0 -3.53,0.5 -5,1.35C7.99,5.08 10,8.3 10,12s-2.01,6.92 -5,8.65C6.47,21.5 8.18,22 10,22c5.52,0 10,-4.48 10,-10S15.52,2 10,2z"/>
|
||||
</vector>
|
|
@ -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="@android:color/white" android:pathData="M9,2c-1.05,0 -2.05,0.16 -3,0.46 4.06,1.27 7,5.06 7,9.54 0,4.48 -2.94,8.27 -7,9.54 0.95,0.3 1.95,0.46 3,0.46 5.52,0 10,-4.48 10,-10S14.52,2 9,2z"/>
|
||||
</vector>
|
|
@ -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="@android:color/white" android:pathData="M20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69L23.31,12 20,8.69zM12,18c-0.89,0 -1.74,-0.2 -2.5,-0.55C11.56,16.5 13,14.42 13,12s-1.44,-4.5 -3.5,-5.45C10.26,6.2 11.11,6 12,6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z"/>
|
||||
</vector>
|
|
@ -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="@android:color/white" android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
|
||||
</vector>
|
|
@ -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="@android:color/white" android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18V6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_baseline_volume_down_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_volume_down_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" 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="@android:color/white" android:pathData="M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM5,9v6h4l5,5V4L9,9H5z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_baseline_volume_mute_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_volume_mute_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" 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="@android:color/white" android:pathData="M7,9v6h4l5,5V4l-5,5H7z"/>
|
||||
</vector>
|
|
@ -1,12 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:tint="?attr/white"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="850.39"
|
||||
android:viewportHeight="850.39">
|
||||
<path
|
||||
android:pathData="M267.01,189.64h99.74v470.26h-99.74z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M463.01,188.79h99.74v470.26h-99.74z"
|
||||
android:pathData="M267.01,189.64h99.74v470.26h-99.74z M463.01,188.79h99.74v470.26h-99.74z"
|
||||
android:fillColor="#fff"/>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_1.xml
Normal file
111
app/src/main/res/drawable/sun_1.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="137"
|
||||
android:viewportHeight="137">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 69.24 35.91 C 62.272 35.91 55.48 38.117 49.843 42.212 C 44.206 46.308 40.008 52.086 37.855 58.712 C 35.702 65.339 35.702 72.481 37.855 79.108 C 40.008 85.734 44.206 91.512 49.843 95.608 C 55.48 99.703 62.272 101.91 69.24 101.91 C 76.208 101.91 83 99.703 88.637 95.608 C 94.274 91.512 98.472 85.734 100.625 79.108 C 102.778 72.481 102.778 65.339 100.625 58.712 C 98.472 52.086 94.274 46.308 88.637 42.212 C 83 38.117 76.208 35.91 69.24 35.91 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 68.91 0.5 L 68.92 0.5 C 70.717 0.5 72.443 1.215 73.714 2.486 C 74.985 3.757 75.7 5.483 75.7 7.28 L 75.7 12.5 C 75.7 13.69 75.387 14.859 74.792 15.89 C 74.197 16.921 73.341 17.777 72.31 18.372 C 71.279 18.967 70.11 19.28 68.92 19.28 L 68.91 19.28 C 67.72 19.28 66.551 18.967 65.52 18.372 C 64.489 17.777 63.633 16.921 63.038 15.89 C 62.443 14.859 62.13 13.69 62.13 12.5 L 62.13 7.28 C 62.13 6.09 62.443 4.921 63.038 3.89 C 63.633 2.859 64.489 2.003 65.52 1.408 C 66.551 0.813 67.72 0.5 68.91 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 68.91 0.5 L 68.92 0.5 C 70.717 0.5 72.443 1.215 73.714 2.486 C 74.985 3.757 75.7 5.483 75.7 7.28 L 75.7 12.5 C 75.7 13.69 75.387 14.859 74.792 15.89 C 74.197 16.921 73.341 17.777 72.31 18.372 C 71.279 18.967 70.11 19.28 68.92 19.28 L 68.91 19.28 C 67.72 19.28 66.551 18.967 65.52 18.372 C 64.489 17.777 63.633 16.921 63.038 15.89 C 62.443 14.859 62.13 13.69 62.13 12.5 L 62.13 7.28 C 62.13 6.09 62.443 4.921 63.038 3.89 C 63.633 2.859 64.489 2.003 65.52 1.408 C 66.551 0.813 67.72 0.5 68.91 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 68.91 118.54 L 68.92 118.54 C 70.717 118.54 72.443 119.255 73.714 120.526 C 74.985 121.797 75.7 123.523 75.7 125.32 L 75.7 130.54 C 75.7 132.337 74.985 134.063 73.714 135.334 C 72.443 136.605 70.717 137.32 68.92 137.32 L 68.91 137.32 C 67.72 137.32 66.551 137.007 65.52 136.412 C 64.489 135.817 63.633 134.961 63.038 133.93 C 62.443 132.899 62.13 131.73 62.13 130.54 L 62.13 125.32 C 62.13 124.13 62.443 122.961 63.038 121.93 C 63.633 120.899 64.489 120.043 65.52 119.448 C 66.551 118.853 67.72 118.54 68.91 118.54"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 68.91 118.54 L 68.92 118.54 C 70.717 118.54 72.443 119.255 73.714 120.526 C 74.985 121.797 75.7 123.523 75.7 125.32 L 75.7 130.54 C 75.7 132.337 74.985 134.063 73.714 135.334 C 72.443 136.605 70.717 137.32 68.92 137.32 L 68.91 137.32 C 67.72 137.32 66.551 137.007 65.52 136.412 C 64.489 135.817 63.633 134.961 63.038 133.93 C 62.443 132.899 62.13 131.73 62.13 130.54 L 62.13 125.32 C 62.13 124.13 62.443 122.961 63.038 121.93 C 63.633 120.899 64.489 120.043 65.52 119.448 C 66.551 118.853 67.72 118.54 68.91 118.54"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 104.007 24.222 L 107.698 20.531 C 108.539 19.69 109.588 19.084 110.737 18.776 C 111.887 18.468 113.097 18.468 114.247 18.776 C 115.396 19.084 116.445 19.69 117.286 20.531 L 117.293 20.538 C 118.135 21.38 118.74 22.428 119.048 23.577 C 119.356 24.727 119.356 25.938 119.048 27.087 C 118.74 28.237 118.135 29.285 117.293 30.126 L 113.602 33.818 C 112.761 34.659 111.712 35.264 110.563 35.572 C 109.413 35.88 108.203 35.88 107.053 35.572 C 105.904 35.264 104.855 34.659 104.014 33.818 L 104.007 33.81 C 103.165 32.969 102.56 31.921 102.252 30.771 C 101.944 29.622 101.944 28.411 102.252 27.261 C 102.56 26.112 103.165 25.064 104.007 24.222"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 104.007 24.222 L 107.698 20.531 C 108.539 19.69 109.588 19.084 110.737 18.776 C 111.887 18.468 113.097 18.468 114.247 18.776 C 115.396 19.084 116.445 19.69 117.286 20.531 L 117.293 20.538 C 118.135 21.38 118.74 22.428 119.048 23.577 C 119.356 24.727 119.356 25.938 119.048 27.087 C 118.74 28.237 118.135 29.285 117.293 30.126 L 113.602 33.818 C 112.761 34.659 111.712 35.264 110.563 35.572 C 109.413 35.88 108.203 35.88 107.053 35.572 C 105.904 35.264 104.855 34.659 104.014 33.818 L 104.007 33.81 C 103.165 32.969 102.56 31.921 102.252 30.771 C 101.944 29.622 101.944 28.411 102.252 27.261 C 102.56 26.112 103.165 25.064 104.007 24.222"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 20.537 107.696 L 24.228 104.005 C 25.069 103.164 26.118 102.559 27.267 102.251 C 28.417 101.943 29.627 101.943 30.777 102.251 C 31.926 102.559 32.975 103.164 33.816 104.005 L 33.823 104.012 C 34.665 104.854 35.27 105.902 35.578 107.052 C 35.886 108.201 35.886 109.412 35.578 110.561 C 35.27 111.711 34.665 112.759 33.823 113.601 L 30.132 117.292 C 29.291 118.133 28.242 118.739 27.093 119.047 C 25.943 119.355 24.733 119.355 23.583 119.047 C 22.434 118.739 21.385 118.133 20.544 117.292 L 20.537 117.285 C 19.695 116.443 19.09 115.395 18.782 114.245 C 18.474 113.096 18.474 111.885 18.782 110.736 C 19.09 109.586 19.695 108.538 20.537 107.696"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 20.537 107.696 L 24.228 104.005 C 25.069 103.164 26.118 102.559 27.267 102.251 C 28.417 101.943 29.627 101.943 30.777 102.251 C 31.926 102.559 32.975 103.164 33.816 104.005 L 33.823 104.012 C 34.665 104.854 35.27 105.902 35.578 107.052 C 35.886 108.201 35.886 109.412 35.578 110.561 C 35.27 111.711 34.665 112.759 33.823 113.601 L 30.132 117.292 C 29.291 118.133 28.242 118.739 27.093 119.047 C 25.943 119.355 24.733 119.355 23.583 119.047 C 22.434 118.739 21.385 118.133 20.544 117.292 L 20.537 117.285 C 19.695 116.443 19.09 115.395 18.782 114.245 C 18.474 113.096 18.474 111.885 18.782 110.736 C 19.09 109.586 19.695 108.538 20.537 107.696"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 125.32 62.13 L 130.54 62.13 C 132.337 62.13 134.063 62.845 135.334 64.116 C 136.605 65.387 137.32 67.113 137.32 68.91 L 137.32 68.92 C 137.32 70.717 136.605 72.443 135.334 73.714 C 134.063 74.985 132.337 75.7 130.54 75.7 L 125.32 75.7 C 123.523 75.7 121.797 74.985 120.526 73.714 C 119.255 72.443 118.54 70.717 118.54 68.92 L 118.54 68.91 C 118.54 67.72 118.853 66.551 119.448 65.52 C 120.043 64.489 120.899 63.633 121.93 63.038 C 122.961 62.443 124.13 62.13 125.32 62.13"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 125.32 62.13 L 130.54 62.13 C 132.337 62.13 134.063 62.845 135.334 64.116 C 136.605 65.387 137.32 67.113 137.32 68.91 L 137.32 68.92 C 137.32 70.717 136.605 72.443 135.334 73.714 C 134.063 74.985 132.337 75.7 130.54 75.7 L 125.32 75.7 C 123.523 75.7 121.797 74.985 120.526 73.714 C 119.255 72.443 118.54 70.717 118.54 68.92 L 118.54 68.91 C 118.54 67.72 118.853 66.551 119.448 65.52 C 120.043 64.489 120.899 63.633 121.93 63.038 C 122.961 62.443 124.13 62.13 125.32 62.13"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 62.13 L 12.5 62.13 C 13.69 62.13 14.859 62.443 15.89 63.038 C 16.921 63.633 17.777 64.489 18.372 65.52 C 18.967 66.551 19.28 67.72 19.28 68.91 L 19.28 68.92 C 19.28 70.11 18.967 71.279 18.372 72.31 C 17.777 73.341 16.921 74.197 15.89 74.792 C 14.859 75.387 13.69 75.7 12.5 75.7 L 7.28 75.7 C 5.483 75.7 3.757 74.985 2.486 73.714 C 1.215 72.443 0.5 70.717 0.5 68.92 L 0.5 68.91 C 0.5 67.72 0.813 66.551 1.408 65.52 C 2.003 64.489 2.859 63.633 3.89 63.038 C 4.921 62.443 6.09 62.13 7.28 62.13"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 62.13 L 12.5 62.13 C 13.69 62.13 14.859 62.443 15.89 63.038 C 16.921 63.633 17.777 64.489 18.372 65.52 C 18.967 66.551 19.28 67.72 19.28 68.91 L 19.28 68.92 C 19.28 70.11 18.967 71.279 18.372 72.31 C 17.777 73.341 16.921 74.197 15.89 74.792 C 14.859 75.387 13.69 75.7 12.5 75.7 L 7.28 75.7 C 5.483 75.7 3.757 74.985 2.486 73.714 C 1.215 72.443 0.5 70.717 0.5 68.92 L 0.5 68.91 C 0.5 67.72 0.813 66.551 1.408 65.52 C 2.003 64.489 2.859 63.633 3.89 63.038 C 4.921 62.443 6.09 62.13 7.28 62.13"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 104.009 104.017 L 104.016 104.01 C 104.858 103.169 105.906 102.563 107.055 102.255 C 108.205 101.947 109.416 101.947 110.565 102.255 C 111.715 102.563 112.763 103.169 113.604 104.01 L 117.295 107.701 C 118.137 108.543 118.742 109.591 119.05 110.741 C 119.358 111.89 119.358 113.101 119.05 114.25 C 118.742 115.4 118.137 116.448 117.295 117.29 L 117.288 117.297 C 116.447 118.138 115.399 118.744 114.249 119.052 C 113.1 119.36 111.889 119.36 110.739 119.052 C 109.59 118.744 108.542 118.138 107.7 117.297 L 104.009 113.606 C 103.167 112.764 102.562 111.716 102.254 110.566 C 101.946 109.417 101.946 108.206 102.254 107.057 C 102.562 105.907 103.167 104.859 104.009 104.017"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 104.009 104.017 L 104.016 104.01 C 104.858 103.169 105.906 102.563 107.055 102.255 C 108.205 101.947 109.416 101.947 110.565 102.255 C 111.715 102.563 112.763 103.169 113.604 104.01 L 117.295 107.701 C 118.137 108.543 118.742 109.591 119.05 110.741 C 119.358 111.89 119.358 113.101 119.05 114.25 C 118.742 115.4 118.137 116.448 117.295 117.29 L 117.288 117.297 C 116.447 118.138 115.399 118.744 114.249 119.052 C 113.1 119.36 111.889 119.36 110.739 119.052 C 109.59 118.744 108.542 118.138 107.7 117.297 L 104.009 113.606 C 103.167 112.764 102.562 111.716 102.254 110.566 C 101.946 109.417 101.946 108.206 102.254 107.057 C 102.562 105.907 103.167 104.859 104.009 104.017"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 20.542 20.54 L 20.549 20.533 C 21.39 19.692 22.439 19.086 23.588 18.778 C 24.738 18.47 25.948 18.47 27.098 18.778 C 28.247 19.086 29.296 19.692 30.137 20.533 L 33.828 24.224 C 34.67 25.066 35.275 26.114 35.583 27.264 C 35.891 28.413 35.891 29.624 35.583 30.773 C 35.275 31.923 34.67 32.971 33.828 33.813 L 33.821 33.82 C 32.98 34.661 31.931 35.267 30.782 35.575 C 29.632 35.883 28.422 35.883 27.272 35.575 C 26.123 35.267 25.074 34.661 24.233 33.82 L 20.542 30.129 C 19.7 29.287 19.095 28.239 18.787 27.089 C 18.479 25.94 18.479 24.729 18.787 23.58 C 19.095 22.43 19.7 21.382 20.542 20.54"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 20.542 20.54 L 20.549 20.533 C 21.39 19.692 22.439 19.086 23.588 18.778 C 24.738 18.47 25.948 18.47 27.098 18.778 C 28.247 19.086 29.296 19.692 30.137 20.533 L 33.828 24.224 C 34.67 25.066 35.275 26.114 35.583 27.264 C 35.891 28.413 35.891 29.624 35.583 30.773 C 35.275 31.923 34.67 32.971 33.828 33.813 L 33.821 33.82 C 32.98 34.661 31.931 35.267 30.782 35.575 C 29.632 35.883 28.422 35.883 27.272 35.575 C 26.123 35.267 25.074 34.661 24.233 33.82 L 20.542 30.129 C 19.7 29.287 19.095 28.239 18.787 27.089 C 18.479 25.94 18.479 24.729 18.787 23.58 C 19.095 22.43 19.7 21.382 20.542 20.54"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_2.xml
Normal file
111
app/src/main/res/drawable/sun_2.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="26.14dp"
|
||||
android:height="26.14dp"
|
||||
android:viewportWidth="149"
|
||||
android:viewportHeight="149">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 74.99 41.67 C 66.241 41.67 57.842 45.149 51.655 51.335 C 45.469 57.522 41.99 65.921 41.99 74.67 C 41.99 83.419 45.469 91.818 51.655 98.005 C 57.842 104.191 66.241 107.67 74.99 107.67 C 83.739 107.67 92.138 104.191 98.325 98.005 C 104.511 91.818 107.99 83.419 107.99 74.67 C 107.99 65.921 104.511 57.522 98.325 51.335 C 92.138 45.149 83.739 41.67 74.99 41.67 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 74.66 0.5 L 74.67 0.5 C 76.467 0.5 78.193 1.215 79.464 2.486 C 80.735 3.757 81.45 5.483 81.45 7.28 L 81.45 18.26 C 81.45 20.057 80.735 21.783 79.464 23.054 C 78.193 24.325 76.467 25.04 74.67 25.04 L 74.66 25.04 C 72.863 25.04 71.137 24.325 69.866 23.054 C 68.595 21.783 67.88 20.057 67.88 18.26 L 67.88 7.28 C 67.88 5.483 68.595 3.757 69.866 2.486 C 71.137 1.215 72.863 0.5 74.66 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 74.66 0.5 L 74.67 0.5 C 76.467 0.5 78.193 1.215 79.464 2.486 C 80.735 3.757 81.45 5.483 81.45 7.28 L 81.45 18.26 C 81.45 20.057 80.735 21.783 79.464 23.054 C 78.193 24.325 76.467 25.04 74.67 25.04 L 74.66 25.04 C 72.863 25.04 71.137 24.325 69.866 23.054 C 68.595 21.783 67.88 20.057 67.88 18.26 L 67.88 7.28 C 67.88 5.483 68.595 3.757 69.866 2.486 C 71.137 1.215 72.863 0.5 74.66 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 74.66 124.3 L 74.67 124.3 C 76.467 124.3 78.193 125.015 79.464 126.286 C 80.735 127.557 81.45 129.283 81.45 131.08 L 81.45 142.06 C 81.45 143.857 80.735 145.583 79.464 146.854 C 78.193 148.125 76.467 148.84 74.67 148.84 L 74.66 148.84 C 72.863 148.84 71.137 148.125 69.866 146.854 C 68.595 145.583 67.88 143.857 67.88 142.06 L 67.88 131.08 C 67.88 129.283 68.595 127.557 69.866 126.286 C 71.137 125.015 72.863 124.3 74.66 124.3"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 74.66 124.3 L 74.67 124.3 C 76.467 124.3 78.193 125.015 79.464 126.286 C 80.735 127.557 81.45 129.283 81.45 131.08 L 81.45 142.06 C 81.45 143.857 80.735 145.583 79.464 146.854 C 78.193 148.125 76.467 148.84 74.67 148.84 L 74.66 148.84 C 72.863 148.84 71.137 148.125 69.866 146.854 C 68.595 145.583 67.88 143.857 67.88 142.06 L 67.88 131.08 C 67.88 129.283 68.595 127.557 69.866 126.286 C 71.137 125.015 72.863 124.3 74.66 124.3"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 109.76 29.988 L 117.524 22.224 C 118.366 21.382 119.414 20.777 120.564 20.469 C 121.713 20.161 122.924 20.161 124.073 20.469 C 125.223 20.777 126.271 21.382 127.113 22.224 L 127.12 22.231 C 127.961 23.072 128.567 24.121 128.875 25.27 C 129.183 26.42 129.183 27.63 128.875 28.78 C 128.567 29.929 127.961 30.978 127.12 31.819 L 119.356 39.583 C 118.514 40.425 117.466 41.03 116.316 41.338 C 115.167 41.646 113.956 41.646 112.807 41.338 C 111.657 41.03 110.609 40.425 109.767 39.583 L 109.76 39.576 C 108.919 38.735 108.314 37.686 108.005 36.537 C 107.697 35.387 107.697 34.177 108.005 33.027 C 108.314 31.878 108.919 30.829 109.76 29.988"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 109.76 29.988 L 117.524 22.224 C 118.366 21.382 119.414 20.777 120.564 20.469 C 121.713 20.161 122.924 20.161 124.073 20.469 C 125.223 20.777 126.271 21.382 127.113 22.224 L 127.12 22.231 C 127.961 23.072 128.567 24.121 128.875 25.27 C 129.183 26.42 129.183 27.63 128.875 28.78 C 128.567 29.929 127.961 30.978 127.12 31.819 L 119.356 39.583 C 118.514 40.425 117.466 41.03 116.316 41.338 C 115.167 41.646 113.956 41.646 112.807 41.338 C 111.657 41.03 110.609 40.425 109.767 39.583 L 109.76 39.576 C 108.919 38.735 108.314 37.686 108.005 36.537 C 107.697 35.387 107.697 34.177 108.005 33.027 C 108.314 31.878 108.919 30.829 109.76 29.988"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 22.22 117.528 L 29.984 109.764 C 30.826 108.922 31.874 108.317 33.024 108.009 C 34.173 107.701 35.384 107.701 36.533 108.009 C 37.683 108.317 38.731 108.922 39.573 109.764 L 39.58 109.771 C 40.421 110.612 41.027 111.661 41.335 112.81 C 41.643 113.96 41.643 115.17 41.335 116.32 C 41.027 117.469 40.421 118.518 39.58 119.359 L 31.816 127.123 C 30.974 127.965 29.926 128.57 28.776 128.878 C 27.627 129.186 26.416 129.186 25.267 128.878 C 24.117 128.57 23.069 127.965 22.227 127.123 L 22.22 127.116 C 21.379 126.275 20.774 125.226 20.465 124.077 C 20.157 122.927 20.157 121.717 20.465 120.567 C 20.774 119.418 21.379 118.369 22.22 117.528"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 22.22 117.528 L 29.984 109.764 C 30.826 108.922 31.874 108.317 33.024 108.009 C 34.173 107.701 35.384 107.701 36.533 108.009 C 37.683 108.317 38.731 108.922 39.573 109.764 L 39.58 109.771 C 40.421 110.612 41.027 111.661 41.335 112.81 C 41.643 113.96 41.643 115.17 41.335 116.32 C 41.027 117.469 40.421 118.518 39.58 119.359 L 31.816 127.123 C 30.974 127.965 29.926 128.57 28.776 128.878 C 27.627 129.186 26.416 129.186 25.267 128.878 C 24.117 128.57 23.069 127.965 22.227 127.123 L 22.22 127.116 C 21.379 126.275 20.774 125.226 20.465 124.077 C 20.157 122.927 20.157 121.717 20.465 120.567 C 20.774 119.418 21.379 118.369 22.22 117.528"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 131.08 67.88 L 142.06 67.88 C 143.857 67.88 145.583 68.595 146.854 69.866 C 148.125 71.137 148.84 72.863 148.84 74.66 L 148.84 74.67 C 148.84 76.467 148.125 78.193 146.854 79.464 C 145.583 80.735 143.857 81.45 142.06 81.45 L 131.08 81.45 C 129.283 81.45 127.557 80.735 126.286 79.464 C 125.015 78.193 124.3 76.467 124.3 74.67 L 124.3 74.66 C 124.3 72.863 125.015 71.137 126.286 69.866 C 127.557 68.595 129.283 67.88 131.08 67.88"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 131.08 67.88 L 142.06 67.88 C 143.857 67.88 145.583 68.595 146.854 69.866 C 148.125 71.137 148.84 72.863 148.84 74.66 L 148.84 74.67 C 148.84 76.467 148.125 78.193 146.854 79.464 C 145.583 80.735 143.857 81.45 142.06 81.45 L 131.08 81.45 C 129.283 81.45 127.557 80.735 126.286 79.464 C 125.015 78.193 124.3 76.467 124.3 74.67 L 124.3 74.66 C 124.3 72.863 125.015 71.137 126.286 69.866 C 127.557 68.595 129.283 67.88 131.08 67.88"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 67.88 L 18.26 67.88 C 20.057 67.88 21.783 68.595 23.054 69.866 C 24.325 71.137 25.04 72.863 25.04 74.66 L 25.04 74.67 C 25.04 76.467 24.325 78.193 23.054 79.464 C 21.783 80.735 20.057 81.45 18.26 81.45 L 7.28 81.45 C 5.483 81.45 3.757 80.735 2.486 79.464 C 1.215 78.193 0.5 76.467 0.5 74.67 L 0.5 74.66 C 0.5 72.863 1.215 71.137 2.486 69.866 C 3.757 68.595 5.483 67.88 7.28 67.88"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 67.88 L 18.26 67.88 C 20.057 67.88 21.783 68.595 23.054 69.866 C 24.325 71.137 25.04 72.863 25.04 74.66 L 25.04 74.67 C 25.04 76.467 24.325 78.193 23.054 79.464 C 21.783 80.735 20.057 81.45 18.26 81.45 L 7.28 81.45 C 5.483 81.45 3.757 80.735 2.486 79.464 C 1.215 78.193 0.5 76.467 0.5 74.67 L 0.5 74.66 C 0.5 72.863 1.215 71.137 2.486 69.866 C 3.757 68.595 5.483 67.88 7.28 67.88"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 109.76 109.764 L 109.767 109.757 C 110.609 108.915 111.657 108.31 112.807 108.002 C 113.956 107.694 115.167 107.694 116.316 108.002 C 117.466 108.31 118.514 108.915 119.356 109.757 L 127.12 117.521 C 127.961 118.362 128.567 119.411 128.875 120.56 C 129.183 121.71 129.183 122.92 128.875 124.07 C 128.567 125.219 127.961 126.268 127.12 127.109 L 127.113 127.116 C 126.271 127.958 125.223 128.563 124.073 128.871 C 122.924 129.179 121.713 129.179 120.564 128.871 C 119.414 128.563 118.366 127.958 117.524 127.116 L 109.76 119.352 C 108.919 118.511 108.314 117.462 108.006 116.313 C 107.698 115.163 107.698 113.953 108.006 112.803 C 108.314 111.654 108.919 110.605 109.76 109.764"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 109.76 109.764 L 109.767 109.757 C 110.609 108.915 111.657 108.31 112.807 108.002 C 113.956 107.694 115.167 107.694 116.316 108.002 C 117.466 108.31 118.514 108.915 119.356 109.757 L 127.12 117.521 C 127.961 118.362 128.567 119.411 128.875 120.56 C 129.183 121.71 129.183 122.92 128.875 124.07 C 128.567 125.219 127.961 126.268 127.12 127.109 L 127.113 127.116 C 126.271 127.958 125.223 128.563 124.073 128.871 C 122.924 129.179 121.713 129.179 120.564 128.871 C 119.414 128.563 118.366 127.958 117.524 127.116 L 109.76 119.352 C 108.919 118.511 108.314 117.462 108.006 116.313 C 107.698 115.163 107.698 113.953 108.006 112.803 C 108.314 111.654 108.919 110.605 109.76 109.764"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 22.22 22.224 L 22.227 22.217 C 23.069 21.375 24.117 20.77 25.267 20.462 C 26.416 20.154 27.627 20.154 28.776 20.462 C 29.926 20.77 30.974 21.375 31.816 22.217 L 39.58 29.981 C 40.421 30.822 41.026 31.871 41.334 33.02 C 41.642 34.17 41.642 35.38 41.334 36.53 C 41.026 37.679 40.421 38.728 39.58 39.569 L 39.573 39.576 C 38.731 40.418 37.683 41.023 36.533 41.331 C 35.384 41.639 34.173 41.639 33.024 41.331 C 31.874 41.023 30.826 40.418 29.984 39.576 L 22.22 31.812 C 21.379 30.971 20.773 29.922 20.465 28.773 C 20.157 27.623 20.157 26.413 20.465 25.263 C 20.773 24.114 21.379 23.065 22.22 22.224"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 22.22 22.224 L 22.227 22.217 C 23.069 21.375 24.117 20.77 25.267 20.462 C 26.416 20.154 27.627 20.154 28.776 20.462 C 29.926 20.77 30.974 21.375 31.816 22.217 L 39.58 29.981 C 40.421 30.822 41.026 31.871 41.334 33.02 C 41.642 34.17 41.642 35.38 41.334 36.53 C 41.026 37.679 40.421 38.728 39.58 39.569 L 39.573 39.576 C 38.731 40.418 37.683 41.023 36.533 41.331 C 35.384 41.639 34.173 41.639 33.024 41.331 C 31.874 41.023 30.826 40.418 29.984 39.576 L 22.22 31.812 C 21.379 30.971 20.773 29.922 20.465 28.773 C 20.157 27.623 20.157 26.413 20.465 25.263 C 20.773 24.114 21.379 23.065 22.22 22.224"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_3.xml
Normal file
111
app/src/main/res/drawable/sun_3.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="27.19dp"
|
||||
android:height="27.19dp"
|
||||
android:viewportWidth="155"
|
||||
android:viewportHeight="155">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 77.86 44.54 C 69.111 44.54 60.712 48.019 54.525 54.205 C 48.339 60.392 44.86 68.791 44.86 77.54 C 44.86 86.289 48.339 94.688 54.525 100.875 C 60.712 107.061 69.111 110.54 77.86 110.54 C 86.609 110.54 95.008 107.061 101.195 100.875 C 107.381 94.688 110.86 86.289 110.86 77.54 C 110.86 68.791 107.381 60.392 101.195 54.205 C 95.008 48.019 86.609 44.54 77.86 44.54 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 77.53 0.5 L 77.54 0.5 C 79.337 0.5 81.063 1.215 82.334 2.486 C 83.605 3.757 84.32 5.483 84.32 7.28 L 84.32 21.13 C 84.32 22.32 84.007 23.489 83.412 24.52 C 82.817 25.551 81.961 26.407 80.93 27.002 C 79.899 27.597 78.73 27.91 77.54 27.91 L 77.53 27.91 C 75.733 27.91 74.007 27.195 72.736 25.924 C 71.465 24.653 70.75 22.927 70.75 21.13 L 70.75 7.28 C 70.75 5.483 71.465 3.757 72.736 2.486 C 74.007 1.215 75.733 0.5 77.53 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 77.53 0.5 L 77.54 0.5 C 79.337 0.5 81.063 1.215 82.334 2.486 C 83.605 3.757 84.32 5.483 84.32 7.28 L 84.32 21.13 C 84.32 22.32 84.007 23.489 83.412 24.52 C 82.817 25.551 81.961 26.407 80.93 27.002 C 79.899 27.597 78.73 27.91 77.54 27.91 L 77.53 27.91 C 75.733 27.91 74.007 27.195 72.736 25.924 C 71.465 24.653 70.75 22.927 70.75 21.13 L 70.75 7.28 C 70.75 5.483 71.465 3.757 72.736 2.486 C 74.007 1.215 75.733 0.5 77.53 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 77.53 127.17 L 77.54 127.17 C 79.337 127.17 81.063 127.885 82.334 129.156 C 83.605 130.427 84.32 132.153 84.32 133.95 L 84.32 147.8 C 84.32 149.597 83.605 151.323 82.334 152.594 C 81.063 153.865 79.337 154.58 77.54 154.58 L 77.53 154.58 C 75.733 154.58 74.007 153.865 72.736 152.594 C 71.465 151.323 70.75 149.597 70.75 147.8 L 70.75 133.95 C 70.75 132.153 71.465 130.427 72.736 129.156 C 74.007 127.885 75.733 127.17 77.53 127.17"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 77.53 127.17 L 77.54 127.17 C 79.337 127.17 81.063 127.885 82.334 129.156 C 83.605 130.427 84.32 132.153 84.32 133.95 L 84.32 147.8 C 84.32 149.597 83.605 151.323 82.334 152.594 C 81.063 153.865 79.337 154.58 77.54 154.58 L 77.53 154.58 C 75.733 154.58 74.007 153.865 72.736 152.594 C 71.465 151.323 70.75 149.597 70.75 147.8 L 70.75 133.95 C 70.75 132.153 71.465 130.427 72.736 129.156 C 74.007 127.885 75.733 127.17 77.53 127.17"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 112.629 32.861 L 122.423 23.067 C 123.694 21.796 125.419 21.081 127.217 21.081 C 129.014 21.081 130.74 21.796 132.011 23.067 L 132.018 23.074 C 132.859 23.916 133.465 24.964 133.773 26.114 C 134.081 27.263 134.081 28.474 133.773 29.623 C 133.465 30.773 132.859 31.821 132.018 32.663 L 122.225 42.456 C 121.383 43.297 120.335 43.903 119.185 44.211 C 118.036 44.519 116.825 44.519 115.676 44.211 C 114.526 43.903 113.478 43.297 112.636 42.456 L 112.629 42.449 C 111.788 41.607 111.182 40.559 110.874 39.409 C 110.566 38.26 110.566 37.049 110.874 35.9 C 111.182 34.75 111.788 33.702 112.629 32.861"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 112.629 32.861 L 122.423 23.067 C 123.694 21.796 125.419 21.081 127.217 21.081 C 129.014 21.081 130.74 21.796 132.011 23.067 L 132.018 23.074 C 132.859 23.916 133.465 24.964 133.773 26.114 C 134.081 27.263 134.081 28.474 133.773 29.623 C 133.465 30.773 132.859 31.821 132.018 32.663 L 122.225 42.456 C 121.383 43.297 120.335 43.903 119.185 44.211 C 118.036 44.519 116.825 44.519 115.676 44.211 C 114.526 43.903 113.478 43.297 112.636 42.456 L 112.629 42.449 C 111.788 41.607 111.182 40.559 110.874 39.409 C 110.566 38.26 110.566 37.049 110.874 35.9 C 111.182 34.75 111.788 33.702 112.629 32.861"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 23.059 122.417 L 32.853 112.624 C 34.124 111.353 35.849 110.638 37.647 110.638 C 39.444 110.638 41.17 111.353 42.441 112.624 L 42.448 112.631 C 43.289 113.473 43.895 114.521 44.203 115.671 C 44.511 116.82 44.511 118.031 44.203 119.18 C 43.895 120.33 43.289 121.378 42.448 122.219 L 32.655 132.013 C 31.813 132.854 30.765 133.46 29.615 133.768 C 28.466 134.076 27.255 134.076 26.106 133.768 C 24.956 133.46 23.908 132.854 23.066 132.013 L 23.059 132.006 C 22.218 131.164 21.612 130.116 21.304 128.966 C 20.996 127.817 20.996 126.606 21.304 125.457 C 21.612 124.307 22.218 123.259 23.059 122.417"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 23.059 122.417 L 32.853 112.624 C 34.124 111.353 35.849 110.638 37.647 110.638 C 39.444 110.638 41.17 111.353 42.441 112.624 L 42.448 112.631 C 43.289 113.473 43.895 114.521 44.203 115.671 C 44.511 116.82 44.511 118.031 44.203 119.18 C 43.895 120.33 43.289 121.378 42.448 122.219 L 32.655 132.013 C 31.813 132.854 30.765 133.46 29.615 133.768 C 28.466 134.076 27.255 134.076 26.106 133.768 C 24.956 133.46 23.908 132.854 23.066 132.013 L 23.059 132.006 C 22.218 131.164 21.612 130.116 21.304 128.966 C 20.996 127.817 20.996 126.606 21.304 125.457 C 21.612 124.307 22.218 123.259 23.059 122.417"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 133.95 70.75 L 147.8 70.75 C 149.597 70.75 151.323 71.465 152.594 72.736 C 153.865 74.007 154.58 75.733 154.58 77.53 L 154.58 77.54 C 154.58 79.337 153.865 81.063 152.594 82.334 C 151.323 83.605 149.597 84.32 147.8 84.32 L 133.95 84.32 C 132.153 84.32 130.427 83.605 129.156 82.334 C 127.885 81.063 127.17 79.337 127.17 77.54 L 127.17 77.53 C 127.17 75.733 127.885 74.007 129.156 72.736 C 130.427 71.465 132.153 70.75 133.95 70.75"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 133.95 70.75 L 147.8 70.75 C 149.597 70.75 151.323 71.465 152.594 72.736 C 153.865 74.007 154.58 75.733 154.58 77.53 L 154.58 77.54 C 154.58 79.337 153.865 81.063 152.594 82.334 C 151.323 83.605 149.597 84.32 147.8 84.32 L 133.95 84.32 C 132.153 84.32 130.427 83.605 129.156 82.334 C 127.885 81.063 127.17 79.337 127.17 77.54 L 127.17 77.53 C 127.17 75.733 127.885 74.007 129.156 72.736 C 130.427 71.465 132.153 70.75 133.95 70.75"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 70.75 L 21.13 70.75 C 22.32 70.75 23.489 71.063 24.52 71.658 C 25.551 72.253 26.407 73.109 27.002 74.14 C 27.597 75.171 27.91 76.34 27.91 77.53 L 27.91 77.54 C 27.91 78.73 27.597 79.899 27.002 80.93 C 26.407 81.961 25.551 82.817 24.52 83.412 C 23.489 84.007 22.32 84.32 21.13 84.32 L 7.28 84.32 C 5.483 84.32 3.757 83.605 2.486 82.334 C 1.215 81.063 0.5 79.337 0.5 77.54 L 0.5 77.53 C 0.5 75.733 1.215 74.007 2.486 72.736 C 3.757 71.465 5.483 70.75 7.28 70.75"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 70.75 L 21.13 70.75 C 22.32 70.75 23.489 71.063 24.52 71.658 C 25.551 72.253 26.407 73.109 27.002 74.14 C 27.597 75.171 27.91 76.34 27.91 77.53 L 27.91 77.54 C 27.91 78.73 27.597 79.899 27.002 80.93 C 26.407 81.961 25.551 82.817 24.52 83.412 C 23.489 84.007 22.32 84.32 21.13 84.32 L 7.28 84.32 C 5.483 84.32 3.757 83.605 2.486 82.334 C 1.215 81.063 0.5 79.337 0.5 77.54 L 0.5 77.53 C 0.5 75.733 1.215 74.007 2.486 72.736 C 3.757 71.465 5.483 70.75 7.28 70.75"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 112.628 112.633 L 112.635 112.626 C 113.476 111.784 114.525 111.179 115.674 110.871 C 116.824 110.563 118.034 110.563 119.184 110.871 C 120.333 111.179 121.382 111.784 122.223 112.626 L 132.016 122.419 C 132.858 123.26 133.463 124.309 133.771 125.458 C 134.079 126.608 134.079 127.818 133.771 128.968 C 133.463 130.117 132.858 131.166 132.016 132.007 L 132.009 132.014 C 130.738 133.285 129.013 134 127.215 134 C 125.418 134 123.692 133.285 122.421 132.014 L 112.628 122.221 C 111.786 121.38 111.181 120.331 110.873 119.182 C 110.565 118.032 110.565 116.822 110.873 115.672 C 111.181 114.523 111.786 113.474 112.628 112.633"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 112.628 112.633 L 112.635 112.626 C 113.476 111.784 114.525 111.179 115.674 110.871 C 116.824 110.563 118.034 110.563 119.184 110.871 C 120.333 111.179 121.382 111.784 122.223 112.626 L 132.016 122.419 C 132.858 123.26 133.463 124.309 133.771 125.458 C 134.079 126.608 134.079 127.818 133.771 128.968 C 133.463 130.117 132.858 131.166 132.016 132.007 L 132.009 132.014 C 130.738 133.285 129.013 134 127.215 134 C 125.418 134 123.692 133.285 122.421 132.014 L 112.628 122.221 C 111.786 121.38 111.181 120.331 110.873 119.182 C 110.565 118.032 110.565 116.822 110.873 115.672 C 111.181 114.523 111.786 113.474 112.628 112.633"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 23.071 23.063 L 23.078 23.056 C 23.919 22.214 24.968 21.609 26.117 21.301 C 27.267 20.993 28.477 20.993 29.627 21.301 C 30.776 21.609 31.825 22.214 32.666 23.056 L 42.46 32.849 C 43.301 33.69 43.906 34.739 44.214 35.888 C 44.522 37.038 44.522 38.248 44.214 39.398 C 43.906 40.547 43.301 41.596 42.46 42.437 L 42.452 42.444 C 41.611 43.286 40.563 43.891 39.413 44.199 C 38.264 44.507 37.053 44.507 35.903 44.199 C 34.754 43.891 33.706 43.286 32.864 42.444 L 23.071 32.651 C 22.229 31.81 21.624 30.761 21.316 29.612 C 21.008 28.462 21.008 27.252 21.316 26.102 C 21.624 24.953 22.229 23.904 23.071 23.063"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 23.071 23.063 L 23.078 23.056 C 23.919 22.214 24.968 21.609 26.117 21.301 C 27.267 20.993 28.477 20.993 29.627 21.301 C 30.776 21.609 31.825 22.214 32.666 23.056 L 42.46 32.849 C 43.301 33.69 43.906 34.739 44.214 35.888 C 44.522 37.038 44.522 38.248 44.214 39.398 C 43.906 40.547 43.301 41.596 42.46 42.437 L 42.452 42.444 C 41.611 43.286 40.563 43.891 39.413 44.199 C 38.264 44.507 37.053 44.507 35.903 44.199 C 34.754 43.891 33.706 43.286 32.864 42.444 L 23.071 32.651 C 22.229 31.81 21.624 30.761 21.316 29.612 C 21.008 28.462 21.008 27.252 21.316 26.102 C 21.624 24.953 22.229 23.904 23.071 23.063"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_4.xml
Normal file
111
app/src/main/res/drawable/sun_4.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="29.12dp"
|
||||
android:height="29.12dp"
|
||||
android:viewportWidth="166"
|
||||
android:viewportHeight="166">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 83.34 50.01 C 76.372 50.01 69.58 52.217 63.943 56.312 C 58.306 60.408 54.108 66.186 51.955 72.812 C 49.802 79.439 49.802 86.581 51.955 93.208 C 54.108 99.834 58.306 105.612 63.943 109.708 C 69.58 113.803 76.372 116.01 83.34 116.01 C 92.089 116.01 100.488 112.531 106.675 106.345 C 112.861 100.158 116.34 91.759 116.34 83.01 C 116.34 74.261 112.861 65.862 106.675 59.675 C 100.488 53.489 92.089 50.01 83.34 50.01 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 83.01 0.5 L 83.02 0.5 C 84.817 0.5 86.543 1.215 87.814 2.486 C 89.085 3.757 89.8 5.483 89.8 7.28 L 89.8 26.6 C 89.8 28.397 89.085 30.123 87.814 31.394 C 86.543 32.665 84.817 33.38 83.02 33.38 L 83.01 33.38 C 81.213 33.38 79.487 32.665 78.216 31.394 C 76.945 30.123 76.23 28.397 76.23 26.6 L 76.23 7.28 C 76.23 5.483 76.945 3.757 78.216 2.486 C 79.487 1.215 81.213 0.5 83.01 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 83.01 0.5 L 83.02 0.5 C 84.817 0.5 86.543 1.215 87.814 2.486 C 89.085 3.757 89.8 5.483 89.8 7.28 L 89.8 26.6 C 89.8 28.397 89.085 30.123 87.814 31.394 C 86.543 32.665 84.817 33.38 83.02 33.38 L 83.01 33.38 C 81.213 33.38 79.487 32.665 78.216 31.394 C 76.945 30.123 76.23 28.397 76.23 26.6 L 76.23 7.28 C 76.23 5.483 76.945 3.757 78.216 2.486 C 79.487 1.215 81.213 0.5 83.01 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 83.01 132.65 L 83.02 132.65 C 84.817 132.65 86.543 133.365 87.814 134.636 C 89.085 135.907 89.8 137.633 89.8 139.43 L 89.8 158.75 C 89.8 160.547 89.085 162.273 87.814 163.544 C 86.543 164.815 84.817 165.53 83.02 165.53 L 83.01 165.53 C 81.213 165.53 79.487 164.815 78.216 163.544 C 76.945 162.273 76.23 160.547 76.23 158.75 L 76.23 139.43 C 76.23 137.633 76.945 135.907 78.216 134.636 C 79.487 133.365 81.213 132.65 83.01 132.65"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 83.01 132.65 L 83.02 132.65 C 84.817 132.65 86.543 133.365 87.814 134.636 C 89.085 135.907 89.8 137.633 89.8 139.43 L 89.8 158.75 C 89.8 160.547 89.085 162.273 87.814 163.544 C 86.543 164.815 84.817 165.53 83.02 165.53 L 83.01 165.53 C 81.213 165.53 79.487 164.815 78.216 163.544 C 76.945 162.273 76.23 160.547 76.23 158.75 L 76.23 139.43 C 76.23 137.633 76.945 135.907 78.216 134.636 C 79.487 133.365 81.213 132.65 83.01 132.65"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 118.112 38.334 L 131.773 24.673 C 132.614 23.832 133.663 23.226 134.812 22.918 C 135.962 22.61 137.172 22.61 138.322 22.918 C 139.471 23.226 140.52 23.832 141.361 24.673 L 141.368 24.68 C 142.21 25.522 142.815 26.57 143.123 27.72 C 143.431 28.869 143.431 30.08 143.123 31.229 C 142.815 32.379 142.21 33.427 141.368 34.269 L 127.707 47.93 C 126.866 48.771 125.817 49.377 124.668 49.685 C 123.518 49.993 122.308 49.993 121.158 49.685 C 120.009 49.377 118.96 48.771 118.119 47.93 L 118.112 47.923 C 117.27 47.081 116.665 46.033 116.357 44.883 C 116.049 43.734 116.049 42.523 116.357 41.374 C 116.665 40.224 117.27 39.176 118.112 38.334"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 118.112 38.334 L 131.773 24.673 C 132.614 23.832 133.663 23.226 134.812 22.918 C 135.962 22.61 137.172 22.61 138.322 22.918 C 139.471 23.226 140.52 23.832 141.361 24.673 L 141.368 24.68 C 142.21 25.522 142.815 26.57 143.123 27.72 C 143.431 28.869 143.431 30.08 143.123 31.229 C 142.815 32.379 142.21 33.427 141.368 34.269 L 127.707 47.93 C 126.866 48.771 125.817 49.377 124.668 49.685 C 123.518 49.993 122.308 49.993 121.158 49.685 C 120.009 49.377 118.96 48.771 118.119 47.93 L 118.112 47.923 C 117.27 47.081 116.665 46.033 116.357 44.883 C 116.049 43.734 116.049 42.523 116.357 41.374 C 116.665 40.224 117.27 39.176 118.112 38.334"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 24.662 131.769 L 38.323 118.107 C 39.164 117.266 40.213 116.66 41.362 116.352 C 42.512 116.044 43.722 116.044 44.872 116.352 C 46.021 116.66 47.07 117.266 47.911 118.107 L 47.918 118.114 C 48.76 118.956 49.365 120.004 49.673 121.154 C 49.981 122.303 49.981 123.514 49.673 124.663 C 49.365 125.813 48.76 126.861 47.918 127.703 L 34.257 141.364 C 33.416 142.205 32.367 142.811 31.218 143.119 C 30.068 143.427 28.858 143.427 27.708 143.119 C 26.559 142.811 25.51 142.205 24.669 141.364 L 24.662 141.357 C 23.82 140.515 23.215 139.467 22.907 138.318 C 22.599 137.168 22.599 135.957 22.907 134.808 C 23.215 133.658 23.82 132.61 24.662 131.769"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 24.662 131.769 L 38.323 118.107 C 39.164 117.266 40.213 116.66 41.362 116.352 C 42.512 116.044 43.722 116.044 44.872 116.352 C 46.021 116.66 47.07 117.266 47.911 118.107 L 47.918 118.114 C 48.76 118.956 49.365 120.004 49.673 121.154 C 49.981 122.303 49.981 123.514 49.673 124.663 C 49.365 125.813 48.76 126.861 47.918 127.703 L 34.257 141.364 C 33.416 142.205 32.367 142.811 31.218 143.119 C 30.068 143.427 28.858 143.427 27.708 143.119 C 26.559 142.811 25.51 142.205 24.669 141.364 L 24.662 141.357 C 23.82 140.515 23.215 139.467 22.907 138.318 C 22.599 137.168 22.599 135.957 22.907 134.808 C 23.215 133.658 23.82 132.61 24.662 131.769"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 139.43 76.23 L 158.75 76.23 C 160.547 76.23 162.273 76.945 163.544 78.216 C 164.815 79.487 165.53 81.213 165.53 83.01 L 165.53 83.02 C 165.53 84.817 164.815 86.543 163.544 87.814 C 162.273 89.085 160.547 89.8 158.75 89.8 L 139.43 89.8 C 137.633 89.8 135.907 89.085 134.636 87.814 C 133.365 86.543 132.65 84.817 132.65 83.02 L 132.65 83.01 C 132.65 81.213 133.365 79.487 134.636 78.216 C 135.907 76.945 137.633 76.23 139.43 76.23"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 139.43 76.23 L 158.75 76.23 C 160.547 76.23 162.273 76.945 163.544 78.216 C 164.815 79.487 165.53 81.213 165.53 83.01 L 165.53 83.02 C 165.53 84.817 164.815 86.543 163.544 87.814 C 162.273 89.085 160.547 89.8 158.75 89.8 L 139.43 89.8 C 137.633 89.8 135.907 89.085 134.636 87.814 C 133.365 86.543 132.65 84.817 132.65 83.02 L 132.65 83.01 C 132.65 81.213 133.365 79.487 134.636 78.216 C 135.907 76.945 137.633 76.23 139.43 76.23"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 76.23 L 26.6 76.23 C 28.397 76.23 30.123 76.945 31.394 78.216 C 32.665 79.487 33.38 81.213 33.38 83.01 L 33.38 83.02 C 33.38 84.817 32.665 86.543 31.394 87.814 C 30.123 89.085 28.397 89.8 26.6 89.8 L 7.28 89.8 C 6.09 89.8 4.921 89.487 3.89 88.892 C 2.859 88.297 2.003 87.441 1.408 86.41 C 0.813 85.379 0.5 84.21 0.5 83.02 L 0.5 83.01 C 0.5 81.213 1.215 79.487 2.486 78.216 C 3.757 76.945 5.483 76.23 7.28 76.23"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 76.23 L 26.6 76.23 C 28.397 76.23 30.123 76.945 31.394 78.216 C 32.665 79.487 33.38 81.213 33.38 83.01 L 33.38 83.02 C 33.38 84.817 32.665 86.543 31.394 87.814 C 30.123 89.085 28.397 89.8 26.6 89.8 L 7.28 89.8 C 6.09 89.8 4.921 89.487 3.89 88.892 C 2.859 88.297 2.003 87.441 1.408 86.41 C 0.813 85.379 0.5 84.21 0.5 83.02 L 0.5 83.01 C 0.5 81.213 1.215 79.487 2.486 78.216 C 3.757 76.945 5.483 76.23 7.28 76.23"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 118.104 118.115 L 118.111 118.108 C 118.952 117.267 120.001 116.661 121.15 116.353 C 122.3 116.045 123.51 116.045 124.66 116.353 C 125.809 116.661 126.858 117.267 127.699 118.108 L 141.36 131.769 C 142.202 132.611 142.807 133.659 143.115 134.809 C 143.423 135.958 143.423 137.169 143.115 138.318 C 142.807 139.468 142.202 140.516 141.36 141.358 L 141.353 141.365 C 140.512 142.206 139.463 142.812 138.314 143.12 C 137.164 143.428 135.954 143.428 134.804 143.12 C 133.655 142.812 132.607 142.206 131.765 141.365 L 118.104 127.704 C 116.833 126.433 116.118 124.707 116.118 122.909 C 116.118 121.112 116.833 119.386 118.104 118.115"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 118.104 118.115 L 118.111 118.108 C 118.952 117.267 120.001 116.661 121.15 116.353 C 122.3 116.045 123.51 116.045 124.66 116.353 C 125.809 116.661 126.858 117.267 127.699 118.108 L 141.36 131.769 C 142.202 132.611 142.807 133.659 143.115 134.809 C 143.423 135.958 143.423 137.169 143.115 138.318 C 142.807 139.468 142.202 140.516 141.36 141.358 L 141.353 141.365 C 140.512 142.206 139.463 142.812 138.314 143.12 C 137.164 143.428 135.954 143.428 134.804 143.12 C 133.655 142.812 132.607 142.206 131.765 141.365 L 118.104 127.704 C 116.833 126.433 116.118 124.707 116.118 122.909 C 116.118 121.112 116.833 119.386 118.104 118.115"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 24.67 24.665 L 24.677 24.658 C 25.518 23.817 26.567 23.211 27.716 22.903 C 28.866 22.595 30.076 22.595 31.226 22.903 C 32.375 23.211 33.424 23.817 34.265 24.658 L 47.926 38.319 C 48.768 39.161 49.373 40.209 49.681 41.359 C 49.989 42.508 49.989 43.719 49.681 44.868 C 49.373 46.018 48.768 47.066 47.926 47.908 L 47.919 47.915 C 47.078 48.756 46.029 49.362 44.88 49.67 C 43.73 49.978 42.52 49.978 41.37 49.67 C 40.221 49.362 39.172 48.756 38.331 47.915 L 24.67 34.254 C 23.399 32.983 22.684 31.257 22.684 29.459 C 22.684 27.662 23.399 25.936 24.67 24.665"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 24.67 24.665 L 24.677 24.658 C 25.518 23.817 26.567 23.211 27.716 22.903 C 28.866 22.595 30.076 22.595 31.226 22.903 C 32.375 23.211 33.424 23.817 34.265 24.658 L 47.926 38.319 C 48.768 39.161 49.373 40.209 49.681 41.359 C 49.989 42.508 49.989 43.719 49.681 44.868 C 49.373 46.018 48.768 47.066 47.926 47.908 L 47.919 47.915 C 47.078 48.756 46.029 49.362 44.88 49.67 C 43.73 49.978 42.52 49.978 41.37 49.67 C 40.221 49.362 39.172 48.756 38.331 47.915 L 24.67 34.254 C 23.399 32.983 22.684 31.257 22.684 29.459 C 22.684 27.662 23.399 25.936 24.67 24.665"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_5.xml
Normal file
111
app/src/main/res/drawable/sun_5.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="31.0dp"
|
||||
android:height="31.0dp"
|
||||
android:viewportWidth="177"
|
||||
android:viewportHeight="177">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 89.21 55.88 C 80.461 55.88 72.062 59.359 65.875 65.545 C 59.689 71.732 56.21 80.131 56.21 88.88 C 56.21 97.629 59.689 106.028 65.875 112.215 C 72.062 118.401 80.461 121.88 89.21 121.88 C 97.959 121.88 106.358 118.401 112.545 112.215 C 118.731 106.028 122.21 97.629 122.21 88.88 C 122.21 80.131 118.731 71.732 112.545 65.545 C 106.358 59.359 97.959 55.88 89.21 55.88 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 88.88 0.5 L 88.89 0.5 C 90.687 0.5 92.413 1.215 93.684 2.486 C 94.955 3.757 95.67 5.483 95.67 7.28 L 95.67 32.47 C 95.67 34.267 94.955 35.993 93.684 37.264 C 92.413 38.535 90.687 39.25 88.89 39.25 L 88.88 39.25 C 87.083 39.25 85.357 38.535 84.086 37.264 C 82.815 35.993 82.1 34.267 82.1 32.47 L 82.1 7.28 C 82.1 5.483 82.815 3.757 84.086 2.486 C 85.357 1.215 87.083 0.5 88.88 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 88.88 0.5 L 88.89 0.5 C 90.687 0.5 92.413 1.215 93.684 2.486 C 94.955 3.757 95.67 5.483 95.67 7.28 L 95.67 32.47 C 95.67 34.267 94.955 35.993 93.684 37.264 C 92.413 38.535 90.687 39.25 88.89 39.25 L 88.88 39.25 C 87.083 39.25 85.357 38.535 84.086 37.264 C 82.815 35.993 82.1 34.267 82.1 32.47 L 82.1 7.28 C 82.1 5.483 82.815 3.757 84.086 2.486 C 85.357 1.215 87.083 0.5 88.88 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 88.88 138.51 L 88.89 138.51 C 90.687 138.51 92.413 139.225 93.684 140.496 C 94.955 141.767 95.67 143.493 95.67 145.29 L 95.67 170.48 C 95.67 172.277 94.955 174.003 93.684 175.274 C 92.413 176.545 90.687 177.26 88.89 177.26 L 88.88 177.26 C 87.083 177.26 85.357 176.545 84.086 175.274 C 82.815 174.003 82.1 172.277 82.1 170.48 L 82.1 145.29 C 82.1 143.493 82.815 141.767 84.086 140.496 C 85.357 139.225 87.083 138.51 88.88 138.51"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 88.88 138.51 L 88.89 138.51 C 90.687 138.51 92.413 139.225 93.684 140.496 C 94.955 141.767 95.67 143.493 95.67 145.29 L 95.67 170.48 C 95.67 172.277 94.955 174.003 93.684 175.274 C 92.413 176.545 90.687 177.26 88.89 177.26 L 88.88 177.26 C 87.083 177.26 85.357 176.545 84.086 175.274 C 82.815 174.003 82.1 172.277 82.1 170.48 L 82.1 145.29 C 82.1 143.493 82.815 141.767 84.086 140.496 C 85.357 139.225 87.083 138.51 88.88 138.51"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 123.973 44.202 L 141.785 26.39 C 142.626 25.548 143.675 24.943 144.824 24.635 C 145.974 24.327 147.184 24.327 148.334 24.635 C 149.483 24.943 150.532 25.548 151.373 26.39 L 151.38 26.397 C 152.222 27.238 152.827 28.287 153.135 29.436 C 153.443 30.586 153.443 31.796 153.135 32.946 C 152.827 34.095 152.222 35.144 151.38 35.985 L 133.568 53.797 C 132.297 55.068 130.571 55.783 128.774 55.783 C 126.977 55.783 125.251 55.068 123.98 53.797 L 123.973 53.79 C 123.131 52.949 122.526 51.9 122.218 50.751 C 121.91 49.601 121.91 48.391 122.218 47.241 C 122.526 46.092 123.131 45.043 123.973 44.202"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 123.973 44.202 L 141.785 26.39 C 142.626 25.548 143.675 24.943 144.824 24.635 C 145.974 24.327 147.184 24.327 148.334 24.635 C 149.483 24.943 150.532 25.548 151.373 26.39 L 151.38 26.397 C 152.222 27.238 152.827 28.287 153.135 29.436 C 153.443 30.586 153.443 31.796 153.135 32.946 C 152.827 34.095 152.222 35.144 151.38 35.985 L 133.568 53.797 C 132.297 55.068 130.571 55.783 128.774 55.783 C 126.977 55.783 125.251 55.068 123.98 53.797 L 123.973 53.79 C 123.131 52.949 122.526 51.9 122.218 50.751 C 121.91 49.601 121.91 48.391 122.218 47.241 C 122.526 46.092 123.131 45.043 123.973 44.202"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 26.39 141.792 L 44.202 123.98 C 45.043 123.138 46.092 122.533 47.241 122.225 C 48.391 121.917 49.601 121.917 50.751 122.225 C 51.9 122.533 52.949 123.138 53.79 123.98 L 53.797 123.987 C 54.639 124.828 55.244 125.877 55.552 127.026 C 55.86 128.176 55.86 129.386 55.552 130.536 C 55.244 131.685 54.639 132.734 53.797 133.575 L 35.985 151.387 C 34.714 152.658 32.989 153.373 31.191 153.373 C 29.394 153.373 27.668 152.658 26.397 151.387 L 26.39 151.38 C 25.548 150.539 24.943 149.49 24.635 148.341 C 24.327 147.191 24.327 145.981 24.635 144.831 C 24.943 143.682 25.548 142.633 26.39 141.792"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 26.39 141.792 L 44.202 123.98 C 45.043 123.138 46.092 122.533 47.241 122.225 C 48.391 121.917 49.601 121.917 50.751 122.225 C 51.9 122.533 52.949 123.138 53.79 123.98 L 53.797 123.987 C 54.639 124.828 55.244 125.877 55.552 127.026 C 55.86 128.176 55.86 129.386 55.552 130.536 C 55.244 131.685 54.639 132.734 53.797 133.575 L 35.985 151.387 C 34.714 152.658 32.989 153.373 31.191 153.373 C 29.394 153.373 27.668 152.658 26.397 151.387 L 26.39 151.38 C 25.548 150.539 24.943 149.49 24.635 148.341 C 24.327 147.191 24.327 145.981 24.635 144.831 C 24.943 143.682 25.548 142.633 26.39 141.792"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 145.29 82.1 L 170.48 82.1 C 172.277 82.1 174.003 82.815 175.274 84.086 C 176.545 85.357 177.26 87.083 177.26 88.88 L 177.26 88.89 C 177.26 90.687 176.545 92.413 175.274 93.684 C 174.003 94.955 172.277 95.67 170.48 95.67 L 145.29 95.67 C 143.493 95.67 141.767 94.955 140.496 93.684 C 139.225 92.413 138.51 90.687 138.51 88.89 L 138.51 88.88 C 138.51 87.083 139.225 85.357 140.496 84.086 C 141.767 82.815 143.493 82.1 145.29 82.1"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 145.29 82.1 L 170.48 82.1 C 172.277 82.1 174.003 82.815 175.274 84.086 C 176.545 85.357 177.26 87.083 177.26 88.88 L 177.26 88.89 C 177.26 90.687 176.545 92.413 175.274 93.684 C 174.003 94.955 172.277 95.67 170.48 95.67 L 145.29 95.67 C 143.493 95.67 141.767 94.955 140.496 93.684 C 139.225 92.413 138.51 90.687 138.51 88.89 L 138.51 88.88 C 138.51 87.083 139.225 85.357 140.496 84.086 C 141.767 82.815 143.493 82.1 145.29 82.1"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 82.1 L 32.47 82.1 C 34.267 82.1 35.993 82.815 37.264 84.086 C 38.535 85.357 39.25 87.083 39.25 88.88 L 39.25 88.89 C 39.25 90.687 38.535 92.413 37.264 93.684 C 35.993 94.955 34.267 95.67 32.47 95.67 L 7.28 95.67 C 5.483 95.67 3.757 94.955 2.486 93.684 C 1.215 92.413 0.5 90.687 0.5 88.89 L 0.5 88.88 C 0.5 87.083 1.215 85.357 2.486 84.086 C 3.757 82.815 5.483 82.1 7.28 82.1"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 82.1 L 32.47 82.1 C 34.267 82.1 35.993 82.815 37.264 84.086 C 38.535 85.357 39.25 87.083 39.25 88.88 L 39.25 88.89 C 39.25 90.687 38.535 92.413 37.264 93.684 C 35.993 94.955 34.267 95.67 32.47 95.67 L 7.28 95.67 C 5.483 95.67 3.757 94.955 2.486 93.684 C 1.215 92.413 0.5 90.687 0.5 88.89 L 0.5 88.88 C 0.5 87.083 1.215 85.357 2.486 84.086 C 3.757 82.815 5.483 82.1 7.28 82.1"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 123.976 123.976 L 123.983 123.969 C 124.825 123.128 125.873 122.522 127.023 122.214 C 128.172 121.906 129.383 121.906 130.532 122.214 C 131.682 122.522 132.73 123.128 133.572 123.969 L 151.384 141.781 C 152.655 143.052 153.37 144.778 153.37 146.575 C 153.37 148.373 152.655 150.099 151.384 151.37 L 151.377 151.377 C 150.535 152.218 149.487 152.823 148.337 153.131 C 147.188 153.439 145.977 153.439 144.828 153.131 C 143.678 152.823 142.63 152.218 141.788 151.377 L 123.976 133.565 C 122.705 132.294 121.991 130.568 121.991 128.77 C 121.991 126.973 122.705 125.247 123.976 123.976"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 123.976 123.976 L 123.983 123.969 C 124.825 123.128 125.873 122.522 127.023 122.214 C 128.172 121.906 129.383 121.906 130.532 122.214 C 131.682 122.522 132.73 123.128 133.572 123.969 L 151.384 141.781 C 152.655 143.052 153.37 144.778 153.37 146.575 C 153.37 148.373 152.655 150.099 151.384 151.37 L 151.377 151.377 C 150.535 152.218 149.487 152.823 148.337 153.131 C 147.188 153.439 145.977 153.439 144.828 153.131 C 143.678 152.823 142.63 152.218 141.788 151.377 L 123.976 133.565 C 122.705 132.294 121.991 130.568 121.991 128.77 C 121.991 126.973 122.705 125.247 123.976 123.976"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 26.386 26.393 L 26.393 26.386 C 27.235 25.545 28.283 24.939 29.433 24.631 C 30.582 24.323 31.793 24.323 32.942 24.631 C 34.092 24.939 35.14 25.545 35.982 26.386 L 53.794 44.198 C 55.065 45.469 55.779 47.195 55.779 48.992 C 55.779 50.79 55.065 52.516 53.794 53.787 L 53.787 53.794 C 52.945 54.635 51.897 55.241 50.747 55.549 C 49.598 55.857 48.387 55.857 47.238 55.549 C 46.088 55.241 45.04 54.635 44.198 53.794 L 26.386 35.982 C 25.115 34.711 24.4 32.985 24.4 31.188 C 24.4 29.39 25.115 27.664 26.386 26.393"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 26.386 26.393 L 26.393 26.386 C 27.235 25.545 28.283 24.939 29.433 24.631 C 30.582 24.323 31.793 24.323 32.942 24.631 C 34.092 24.939 35.14 25.545 35.982 26.386 L 53.794 44.198 C 55.065 45.469 55.779 47.195 55.779 48.992 C 55.779 50.79 55.065 52.516 53.794 53.787 L 53.787 53.794 C 52.945 54.635 51.897 55.241 50.747 55.549 C 49.598 55.857 48.387 55.857 47.238 55.549 C 46.088 55.241 45.04 54.635 44.198 53.794 L 26.386 35.982 C 25.115 34.711 24.4 32.985 24.4 31.188 C 24.4 29.39 25.115 27.664 26.386 26.393"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_6.xml
Normal file
111
app/src/main/res/drawable/sun_6.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="33.15dp"
|
||||
android:height="33.15dp"
|
||||
android:viewportWidth="189"
|
||||
android:viewportHeight="189">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 94.88 61.56 C 86.131 61.56 77.732 65.039 71.545 71.225 C 65.359 77.412 61.88 85.811 61.88 94.56 C 61.88 103.309 65.359 111.708 71.545 117.895 C 77.732 124.081 86.131 127.56 94.88 127.56 C 103.629 127.56 112.028 124.081 118.215 117.895 C 124.401 111.708 127.88 103.309 127.88 94.56 C 127.88 85.811 124.401 77.412 118.215 71.225 C 112.028 65.039 103.629 61.56 94.88 61.56 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 94.56 0.5 L 94.57 0.5 C 96.367 0.5 98.093 1.215 99.364 2.486 C 100.635 3.757 101.35 5.483 101.35 7.28 L 101.35 38.15 C 101.35 39.947 100.635 41.673 99.364 42.944 C 98.093 44.215 96.367 44.93 94.57 44.93 L 94.56 44.93 C 92.763 44.93 91.037 44.215 89.766 42.944 C 88.495 41.673 87.78 39.947 87.78 38.15 L 87.78 7.28 C 87.78 5.483 88.495 3.757 89.766 2.486 C 91.037 1.215 92.763 0.5 94.56 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 94.56 0.5 L 94.57 0.5 C 96.367 0.5 98.093 1.215 99.364 2.486 C 100.635 3.757 101.35 5.483 101.35 7.28 L 101.35 38.15 C 101.35 39.947 100.635 41.673 99.364 42.944 C 98.093 44.215 96.367 44.93 94.57 44.93 L 94.56 44.93 C 92.763 44.93 91.037 44.215 89.766 42.944 C 88.495 41.673 87.78 39.947 87.78 38.15 L 87.78 7.28 C 87.78 5.483 88.495 3.757 89.766 2.486 C 91.037 1.215 92.763 0.5 94.56 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 94.56 144.19 L 94.57 144.19 C 96.367 144.19 98.093 144.905 99.364 146.176 C 100.635 147.447 101.35 149.173 101.35 150.97 L 101.35 181.84 C 101.35 183.637 100.635 185.363 99.364 186.634 C 98.093 187.905 96.367 188.62 94.57 188.62 L 94.56 188.62 C 92.763 188.62 91.037 187.905 89.766 186.634 C 88.495 185.363 87.78 183.637 87.78 181.84 L 87.78 150.97 C 87.78 149.173 88.495 147.447 89.766 146.176 C 91.037 144.905 92.763 144.19 94.56 144.19"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 94.56 144.19 L 94.57 144.19 C 96.367 144.19 98.093 144.905 99.364 146.176 C 100.635 147.447 101.35 149.173 101.35 150.97 L 101.35 181.84 C 101.35 183.637 100.635 185.363 99.364 186.634 C 98.093 187.905 96.367 188.62 94.57 188.62 L 94.56 188.62 C 92.763 188.62 91.037 187.905 89.766 186.634 C 88.495 185.363 87.78 183.637 87.78 181.84 L 87.78 150.97 C 87.78 149.173 88.495 147.447 89.766 146.176 C 91.037 144.905 92.763 144.19 94.56 144.19"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 129.652 49.874 L 151.48 28.046 C 152.322 27.205 153.37 26.599 154.519 26.291 C 155.669 25.983 156.88 25.983 158.029 26.291 C 159.179 26.599 160.227 27.205 161.068 28.046 L 161.075 28.053 C 161.917 28.895 162.522 29.943 162.83 31.092 C 163.138 32.242 163.138 33.453 162.83 34.602 C 162.522 35.752 161.917 36.8 161.075 37.641 L 139.247 59.47 C 138.406 60.311 137.357 60.917 136.208 61.225 C 135.058 61.533 133.848 61.533 132.698 61.225 C 131.549 60.917 130.5 60.311 129.659 59.47 L 129.652 59.463 C 128.81 58.621 128.205 57.573 127.897 56.423 C 127.589 55.274 127.589 54.063 127.897 52.914 C 128.205 51.764 128.81 50.716 129.652 49.874"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 129.652 49.874 L 151.48 28.046 C 152.322 27.205 153.37 26.599 154.519 26.291 C 155.669 25.983 156.88 25.983 158.029 26.291 C 159.179 26.599 160.227 27.205 161.068 28.046 L 161.075 28.053 C 161.917 28.895 162.522 29.943 162.83 31.092 C 163.138 32.242 163.138 33.453 162.83 34.602 C 162.522 35.752 161.917 36.8 161.075 37.641 L 139.247 59.47 C 138.406 60.311 137.357 60.917 136.208 61.225 C 135.058 61.533 133.848 61.533 132.698 61.225 C 131.549 60.917 130.5 60.311 129.659 59.47 L 129.652 59.463 C 128.81 58.621 128.205 57.573 127.897 56.423 C 127.589 55.274 127.589 54.063 127.897 52.914 C 128.205 51.764 128.81 50.716 129.652 49.874"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 28.052 151.479 L 49.88 129.65 C 50.722 128.809 51.77 128.203 52.919 127.895 C 54.069 127.587 55.28 127.587 56.429 127.895 C 57.579 128.203 58.627 128.809 59.468 129.65 L 59.475 129.657 C 60.317 130.499 60.922 131.547 61.23 132.697 C 61.538 133.846 61.538 135.057 61.23 136.206 C 60.922 137.356 60.317 138.404 59.475 139.246 L 37.647 161.074 C 36.806 161.915 35.757 162.521 34.608 162.829 C 33.458 163.137 32.248 163.137 31.098 162.829 C 29.949 162.521 28.9 161.915 28.059 161.074 L 28.052 161.067 C 27.21 160.225 26.605 159.177 26.297 158.028 C 25.989 156.878 25.989 155.667 26.297 154.518 C 26.605 153.368 27.21 152.32 28.052 151.479"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 28.052 151.479 L 49.88 129.65 C 50.722 128.809 51.77 128.203 52.919 127.895 C 54.069 127.587 55.28 127.587 56.429 127.895 C 57.579 128.203 58.627 128.809 59.468 129.65 L 59.475 129.657 C 60.317 130.499 60.922 131.547 61.23 132.697 C 61.538 133.846 61.538 135.057 61.23 136.206 C 60.922 137.356 60.317 138.404 59.475 139.246 L 37.647 161.074 C 36.806 161.915 35.757 162.521 34.608 162.829 C 33.458 163.137 32.248 163.137 31.098 162.829 C 29.949 162.521 28.9 161.915 28.059 161.074 L 28.052 161.067 C 27.21 160.225 26.605 159.177 26.297 158.028 C 25.989 156.878 25.989 155.667 26.297 154.518 C 26.605 153.368 27.21 152.32 28.052 151.479"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 150.97 87.78 L 181.84 87.78 C 183.637 87.78 185.363 88.495 186.634 89.766 C 187.905 91.037 188.62 92.763 188.62 94.56 L 188.62 94.57 C 188.62 96.367 187.905 98.093 186.634 99.364 C 185.363 100.635 183.637 101.35 181.84 101.35 L 150.97 101.35 C 149.173 101.35 147.447 100.635 146.176 99.364 C 144.905 98.093 144.19 96.367 144.19 94.57 L 144.19 94.56 C 144.19 92.763 144.905 91.037 146.176 89.766 C 147.447 88.495 149.173 87.78 150.97 87.78"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 150.97 87.78 L 181.84 87.78 C 183.637 87.78 185.363 88.495 186.634 89.766 C 187.905 91.037 188.62 92.763 188.62 94.56 L 188.62 94.57 C 188.62 96.367 187.905 98.093 186.634 99.364 C 185.363 100.635 183.637 101.35 181.84 101.35 L 150.97 101.35 C 149.173 101.35 147.447 100.635 146.176 99.364 C 144.905 98.093 144.19 96.367 144.19 94.57 L 144.19 94.56 C 144.19 92.763 144.905 91.037 146.176 89.766 C 147.447 88.495 149.173 87.78 150.97 87.78"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 87.78 L 38.15 87.78 C 39.947 87.78 41.673 88.495 42.944 89.766 C 44.215 91.037 44.93 92.763 44.93 94.56 L 44.93 94.57 C 44.93 96.367 44.215 98.093 42.944 99.364 C 41.673 100.635 39.947 101.35 38.15 101.35 L 7.28 101.35 C 6.09 101.35 4.921 101.037 3.89 100.442 C 2.859 99.847 2.003 98.991 1.408 97.96 C 0.813 96.929 0.5 95.76 0.5 94.57 L 0.5 94.56 C 0.5 92.763 1.215 91.037 2.486 89.766 C 3.757 88.495 5.483 87.78 7.28 87.78"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 87.78 L 38.15 87.78 C 39.947 87.78 41.673 88.495 42.944 89.766 C 44.215 91.037 44.93 92.763 44.93 94.56 L 44.93 94.57 C 44.93 96.367 44.215 98.093 42.944 99.364 C 41.673 100.635 39.947 101.35 38.15 101.35 L 7.28 101.35 C 6.09 101.35 4.921 101.037 3.89 100.442 C 2.859 99.847 2.003 98.991 1.408 97.96 C 0.813 96.929 0.5 95.76 0.5 94.57 L 0.5 94.56 C 0.5 92.763 1.215 91.037 2.486 89.766 C 3.757 88.495 5.483 87.78 7.28 87.78"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 129.654 129.655 L 129.661 129.648 C 130.502 128.807 131.551 128.201 132.7 127.893 C 133.85 127.585 135.06 127.585 136.21 127.893 C 137.359 128.201 138.408 128.807 139.249 129.648 L 161.078 151.476 C 161.919 152.318 162.524 153.366 162.832 154.516 C 163.14 155.665 163.14 156.876 162.832 158.025 C 162.524 159.175 161.919 160.223 161.078 161.065 L 161.07 161.072 C 160.229 161.913 159.181 162.519 158.031 162.827 C 156.882 163.135 155.671 163.135 154.521 162.827 C 153.372 162.519 152.324 161.913 151.482 161.072 L 129.654 139.244 C 128.812 138.402 128.207 137.354 127.899 136.204 C 127.591 135.055 127.591 133.844 127.899 132.695 C 128.207 131.545 128.812 130.497 129.654 129.655"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 129.654 129.655 L 129.661 129.648 C 130.502 128.807 131.551 128.201 132.7 127.893 C 133.85 127.585 135.06 127.585 136.21 127.893 C 137.359 128.201 138.408 128.807 139.249 129.648 L 161.078 151.476 C 161.919 152.318 162.524 153.366 162.832 154.516 C 163.14 155.665 163.14 156.876 162.832 158.025 C 162.524 159.175 161.919 160.223 161.078 161.065 L 161.07 161.072 C 160.229 161.913 159.181 162.519 158.031 162.827 C 156.882 163.135 155.671 163.135 154.521 162.827 C 153.372 162.519 152.324 161.913 151.482 161.072 L 129.654 139.244 C 128.812 138.402 128.207 137.354 127.899 136.204 C 127.591 135.055 127.591 133.844 127.899 132.695 C 128.207 131.545 128.812 130.497 129.654 129.655"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 28.05 28.055 L 28.057 28.048 C 28.898 27.207 29.947 26.601 31.096 26.293 C 32.246 25.985 33.456 25.985 34.606 26.293 C 35.755 26.601 36.804 27.207 37.645 28.048 L 59.473 49.876 C 60.315 50.718 60.92 51.766 61.228 52.916 C 61.536 54.065 61.536 55.276 61.228 56.425 C 60.92 57.575 60.315 58.623 59.473 59.465 L 59.466 59.472 C 58.625 60.313 57.576 60.919 56.427 61.227 C 55.277 61.535 54.067 61.535 52.917 61.227 C 51.768 60.919 50.719 60.313 49.878 59.472 L 28.05 37.644 C 27.208 36.802 26.603 35.754 26.295 34.604 C 25.987 33.455 25.987 32.244 26.295 31.095 C 26.603 29.945 27.208 28.897 28.05 28.055"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 28.05 28.055 L 28.057 28.048 C 28.898 27.207 29.947 26.601 31.096 26.293 C 32.246 25.985 33.456 25.985 34.606 26.293 C 35.755 26.601 36.804 27.207 37.645 28.048 L 59.473 49.876 C 60.315 50.718 60.92 51.766 61.228 52.916 C 61.536 54.065 61.536 55.276 61.228 56.425 C 60.92 57.575 60.315 58.623 59.473 59.465 L 59.466 59.472 C 58.625 60.313 57.576 60.919 56.427 61.227 C 55.277 61.535 54.067 61.535 52.917 61.227 C 51.768 60.919 50.719 60.313 49.878 59.472 L 28.05 37.644 C 27.208 36.802 26.603 35.754 26.295 34.604 C 25.987 33.455 25.987 32.244 26.295 31.095 C 26.603 29.945 27.208 28.897 28.05 28.055"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
111
app/src/main/res/drawable/sun_7.xml
Normal file
111
app/src/main/res/drawable/sun_7.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="35.96dp"
|
||||
android:height="35.96dp"
|
||||
android:viewportWidth="205"
|
||||
android:viewportHeight="205">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 103.3 69.97 C 94.551 69.97 86.152 73.449 79.965 79.635 C 73.779 85.822 70.3 94.221 70.3 102.97 C 70.3 111.719 73.779 120.118 79.965 126.305 C 86.152 132.491 94.551 135.97 103.3 135.97 C 112.049 135.97 120.448 132.491 126.635 126.305 C 132.821 120.118 136.3 111.719 136.3 102.97 C 136.3 94.221 132.821 85.822 126.635 79.635 C 120.448 73.449 112.049 69.97 103.3 69.97 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_3"
|
||||
android:pathData="M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_4"
|
||||
android:pathData="M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_5"
|
||||
android:pathData="M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_6"
|
||||
android:pathData="M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<path
|
||||
android:name="path_7"
|
||||
android:pathData="M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_8"
|
||||
android:pathData="M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path_9"
|
||||
android:pathData="M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_10"
|
||||
android:pathData="M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_11"
|
||||
android:pathData="M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_12"
|
||||
android:pathData="M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_13"
|
||||
android:pathData="M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_14"
|
||||
android:pathData="M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
<group android:name="group_3">
|
||||
<path
|
||||
android:name="path_15"
|
||||
android:pathData="M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_16"
|
||||
android:pathData="M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:strokeMiterLimit="10"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -111,7 +111,7 @@
|
|||
android:layout_width="30dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:tint="?attr/textColor"
|
||||
app:tint="?attr/textColor"
|
||||
android:contentDescription="@string/download"/>
|
||||
</FrameLayout>
|
||||
</GridLayout>
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
android:visibility="visible"
|
||||
/>
|
||||
<ImageView
|
||||
android:tint="?attr/white"
|
||||
|
||||
android:visibility="visible"
|
||||
android:layout_marginEnd="10dp"
|
||||
|
@ -97,7 +96,8 @@
|
|||
android:id="@+id/download_header_episode_download"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:contentDescription="@string/download"/>
|
||||
android:contentDescription="@string/download"
|
||||
app:tint="?attr/white" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
18
app/src/main/res/layout/empty_layout.xml
Normal file
18
app/src/main/res/layout/empty_layout.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/mobile_navigation"
|
||||
app:layout_constraintWidth="match_parent"
|
||||
app:layout_constraintHeight="match_parent"
|
||||
app:layout_constraintStart_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="parent"
|
||||
/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -358,7 +358,7 @@
|
|||
android:text="@string/continue_watching"
|
||||
/>
|
||||
<ImageView
|
||||
android:tint="?attr/textColor"
|
||||
app:tint="?attr/textColor"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_baseline_arrow_forward_24"
|
||||
|
@ -451,7 +451,7 @@
|
|||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
<ImageView
|
||||
android:tint="?attr/textColor"
|
||||
app:tint="?attr/textColor"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_baseline_arrow_forward_24"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:keepScreenOn="true"
|
||||
android:id="@+id/player_background"
|
||||
app:backgroundTint="@android:color/black"
|
||||
android:background="@android:color/black"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
|
@ -37,13 +38,14 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/loading_overlay"
|
||||
android:id="@+id/player_loading_overlay"
|
||||
android:background="@android:color/black"
|
||||
android:backgroundTint="@android:color/black"
|
||||
>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:visibility="visible"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:layout_marginTop="70dp"
|
||||
android:layout_gravity="center"
|
||||
app:cornerRadius="4dp"
|
||||
|
@ -61,8 +63,6 @@
|
|||
android:layout_height="45dp">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
|
@ -88,7 +88,7 @@
|
|||
>
|
||||
</ImageView>
|
||||
<ImageView
|
||||
android:id="@+id/video_go_back_holder"
|
||||
android:id="@+id/player_loading_go_back"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
|
@ -132,7 +132,7 @@
|
|||
android:textColor="@color/white"
|
||||
android:id="@+id/video_torrent_seeders"
|
||||
tools:text="17 seeders"
|
||||
app:layout_constraintTop_toBottomOf="@+id/video_title">
|
||||
app:layout_constraintTop_toBottomOf="@+id/player_video_title">
|
||||
</TextView>
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,14 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/result_root"
|
||||
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
>
|
||||
android:focusable="true">
|
||||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
tools:visibility="gone"
|
||||
|
@ -29,31 +28,44 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginBottom="@dimen/loading_margin"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<include layout="@layout/loading_poster"/>
|
||||
|
||||
<include layout="@layout/loading_poster" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginStart="@dimen/loading_margin"
|
||||
android:layout_marginEnd="@dimen/loading_margin"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<include layout="@layout/loading_line"/>
|
||||
<include layout="@layout/loading_line"/>
|
||||
<include layout="@layout/loading_line"/>
|
||||
<include layout="@layout/loading_line"/>
|
||||
<include layout="@layout/loading_line_short"/>
|
||||
|
||||
<include layout="@layout/loading_line" />
|
||||
|
||||
<include layout="@layout/loading_line" />
|
||||
|
||||
<include layout="@layout/loading_line" />
|
||||
|
||||
<include layout="@layout/loading_line" />
|
||||
|
||||
<include layout="@layout/loading_line_short" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView android:layout_width="match_parent" android:layout_height="20dp"
|
||||
tools:ignore="ContentDescription"/>
|
||||
<include layout="@layout/loading_episode"/>
|
||||
<include layout="@layout/loading_episode"/>
|
||||
<include layout="@layout/loading_episode"/>
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
</LinearLayout>
|
||||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
<!--<ProgressBar
|
||||
|
@ -72,6 +84,7 @@
|
|||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="center"
|
||||
style="@style/WhiteButton"
|
||||
|
@ -82,8 +95,8 @@
|
|||
android:text="@string/reload_error"
|
||||
android:id="@+id/result_reload_connectionerror"
|
||||
android:layout_width="wrap_content"
|
||||
android:minWidth="200dp"
|
||||
/>
|
||||
android:minWidth="200dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="center"
|
||||
style="@style/BlackButton"
|
||||
|
@ -94,8 +107,8 @@
|
|||
android:text="@string/result_open_in_browser"
|
||||
android:id="@+id/result_reload_connection_open_in_browser"
|
||||
android:layout_width="wrap_content"
|
||||
android:minWidth="200dp"
|
||||
/>
|
||||
android:minWidth="200dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_margin="5dp"
|
||||
android:gravity="center"
|
||||
|
@ -103,8 +116,7 @@
|
|||
android:id="@+id/result_error_text"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
|
@ -120,6 +132,7 @@
|
|||
android:visibility="visible"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="230dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/result_poster_blur"
|
||||
|
||||
|
@ -129,31 +142,36 @@
|
|||
android:alpha="0"
|
||||
tools:src="@drawable/example_poster"
|
||||
android:background="?attr/primaryGrayBackground"
|
||||
tools:ignore="ContentDescription"/>
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/background_shadow"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
tools:ignore="ContentDescription"/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/result_scroll"
|
||||
android:background="?attr/primaryGrayBackground"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:background="?attr/primaryGrayBackground"
|
||||
android:paddingStart="@dimen/result_padding"
|
||||
android:paddingEnd="@dimen/result_padding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:nextFocusDown="@id/result_bookmark_button"
|
||||
android:nextFocusRight="@id/result_share"
|
||||
|
@ -166,17 +184,17 @@
|
|||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:tint="?attr/white"
|
||||
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||
android:contentDescription="@string/result_go_back">
|
||||
</ImageView>
|
||||
android:contentDescription="@string/go_back"
|
||||
app:tint="?attr/white" />
|
||||
|
||||
<LinearLayout
|
||||
android:gravity="end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:id="@+id/media_route_button_holder"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
>
|
||||
android:layout_gravity="center_vertical|end">
|
||||
|
||||
<androidx.mediarouter.app.MediaRouteButton
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:id="@+id/media_route_button"
|
||||
|
@ -184,8 +202,8 @@
|
|||
android:layout_height="50dp"
|
||||
android:mediaRouteTypes="user"
|
||||
android:visibility="gone"
|
||||
app:mediaRouteButtonTint="?attr/textColor"
|
||||
/>
|
||||
app:mediaRouteButtonTint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:visibility="gone"
|
||||
android:nextFocusUp="@id/result_back"
|
||||
|
@ -196,16 +214,14 @@
|
|||
android:id="@+id/result_add_sync"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tint="?attr/textColor"
|
||||
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_add_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:contentDescription="@string/add_sync">
|
||||
</ImageView>
|
||||
android:contentDescription="@string/add_sync"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:nextFocusUp="@id/result_back"
|
||||
|
@ -216,16 +232,15 @@
|
|||
android:id="@+id/result_share"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tint="?attr/textColor"
|
||||
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_outline_share_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:contentDescription="@string/result_share">
|
||||
</ImageView>
|
||||
android:contentDescription="@string/result_share"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:nextFocusUp="@id/result_back"
|
||||
android:nextFocusDown="@id/result_descript"
|
||||
|
@ -238,13 +253,11 @@
|
|||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tint="?attr/textColor"
|
||||
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_public_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:contentDescription="@string/result_open_in_browser">
|
||||
</ImageView>
|
||||
android:contentDescription="@string/result_open_in_browser"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:nextFocusUp="@id/result_back"
|
||||
|
@ -258,15 +271,14 @@
|
|||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tint="?attr/textColor"
|
||||
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/search_icon"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:contentDescription="@string/result_open_in_browser">
|
||||
</ImageView>
|
||||
android:contentDescription="@string/result_open_in_browser"
|
||||
app:tint="?attr/textColor" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
|
@ -274,6 +286,7 @@
|
|||
android:paddingEnd="@dimen/result_padding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:visibility="visible"
|
||||
android:layout_marginBottom="15dp"
|
||||
|
@ -281,11 +294,13 @@
|
|||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/result_poster_holder"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="140dp">
|
||||
|
||||
<ImageView
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
|
||||
|
@ -294,13 +309,15 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:src="@drawable/example_poster"
|
||||
android:contentDescription="@string/result_poster_img_des"/>
|
||||
android:contentDescription="@string/result_poster_img_des" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginStart="10dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:maxLines="2"
|
||||
android:layout_marginBottom="10dp"
|
||||
|
@ -308,27 +325,20 @@
|
|||
tools:text="The Perfect Run The Perfect Run The Perfect Run"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/textColor" android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:minWidth="0dp"
|
||||
app:iconPadding="0dp"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
style="@style/BlackButton"
|
||||
tools:text="Gogoanime"
|
||||
android:id="@+id/result_meta_site"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginStart="0dp"
|
||||
android:textSize="12sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
style="@style/SmallBlackButton"
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:text="Gogoanime" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_meta_year"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -336,8 +346,8 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:textColor="?attr/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_meta_rating"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -346,8 +356,8 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_meta_duration"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -356,12 +366,13 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:textColor="?attr/textColor"
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
|
@ -374,17 +385,18 @@
|
|||
android:textSize="15sp"
|
||||
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. "
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/background_shadow"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
tools:ignore="ContentDescription"/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_marginTop="0dp"
|
||||
android:paddingTop="0dp"
|
||||
|
@ -405,9 +417,9 @@
|
|||
android:id="@+id/result_bookmark_button"
|
||||
tools:text="Bookmark"
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/BlackButton"
|
||||
>
|
||||
<requestFocus/>
|
||||
style="@style/BlackButton">
|
||||
|
||||
<requestFocus />
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
|
@ -415,16 +427,18 @@
|
|||
android:id="@+id/result_vpn"
|
||||
android:textSize="15sp"
|
||||
tools:text="@string/vpn_torrent"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:layout_marginBottom="5dp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:id="@+id/result_info"
|
||||
android:textSize="15sp"
|
||||
tools:text="@string/provider_info_meta"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/result_tag_holder"
|
||||
|
@ -435,12 +449,12 @@
|
|||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:textStyle="normal"
|
||||
android:textColor="?attr/textColor"
|
||||
/>
|
||||
android:textColor="?attr/textColor" />
|
||||
|
||||
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||
android:id="@+id/result_tag"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginTop="5dp"
|
||||
|
@ -448,6 +462,7 @@
|
|||
android:id="@+id/result_movie_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
|
@ -461,8 +476,8 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/play_movie_button"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
android:layout_width="match_parent">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
android:layout_width="match_parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_season_button"
|
||||
|
@ -479,8 +494,7 @@
|
|||
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_width="match_parent">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
android:layout_width="match_parent" />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:layout_width="match_parent"
|
||||
|
@ -493,7 +507,8 @@
|
|||
android:layout_gravity="end|center_vertical"
|
||||
android:progress="0"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_movie_text_progress"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -501,8 +516,7 @@
|
|||
tools:text="128MB / 237MB"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
</TextView>
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
<!--<TextView
|
||||
android:visibility="gone"
|
||||
|
@ -553,18 +567,21 @@
|
|||
app:spanCount="3"
|
||||
android:id="@+id/result_recommendations"
|
||||
tools:listitem="@layout/search_result_grid"
|
||||
android:orientation="vertical"
|
||||
/>
|
||||
android:orientation="vertical" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_episodes_tab"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
tools:visibility="visible"
|
||||
tools:text="Season 1"
|
||||
|
@ -577,8 +594,8 @@
|
|||
android:visibility="gone"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
style="@style/MultiSelectButton">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
style="@style/MultiSelectButton" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
tools:visibility="visible"
|
||||
tools:text="50-100"
|
||||
|
@ -592,8 +609,7 @@
|
|||
android:visibility="gone"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
style="@style/MultiSelectButton"
|
||||
/>
|
||||
style="@style/MultiSelectButton" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
tools:visibility="visible"
|
||||
|
@ -608,8 +624,8 @@
|
|||
android:visibility="gone"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
style="@style/MultiSelectButton"
|
||||
/>
|
||||
style="@style/MultiSelectButton" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -619,18 +635,44 @@
|
|||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:textStyle="normal"
|
||||
android:textColor="?attr/textColor"
|
||||
/>
|
||||
android:textColor="?attr/textColor" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
tools:visibility="visible"
|
||||
app:shimmer_base_alpha="0.2"
|
||||
app:shimmer_highlight_alpha="0.3"
|
||||
app:shimmer_duration="@integer/loading_time"
|
||||
app:shimmer_auto_start="true"
|
||||
android:id="@+id/result_episode_loading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
|
||||
<include layout="@layout/loading_episode" />
|
||||
</LinearLayout>
|
||||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
<!--<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/result_episode_loading"
|
||||
|
||||
style="@style/Widget.AppCompat.ProgressBar"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp">
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
android:layout_height="50dp" />-->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:id="@+id/result_episodes"
|
||||
|
@ -639,26 +681,26 @@
|
|||
android:paddingBottom="100dp"
|
||||
tools:listitem="@layout/result_episode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:id="@+id/result_bookmark_fab"
|
||||
app:icon="@drawable/ic_baseline_bookmark_24"
|
||||
style="@style/ExtendedFloatingActionButton"
|
||||
tools:ignore="ContentDescription">
|
||||
</com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton>
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<fragment
|
||||
app:customCastBackgroundColor="?attr/primaryBlackBackground"
|
||||
app:castControlButtons="@array/cast_mini_controller_control_buttons"
|
||||
|
@ -667,8 +709,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
class="com.lagradost.cloudstream3.ui.MyMiniControllerFragment"
|
||||
tools:ignore="FragmentTagUsage">
|
||||
</fragment>
|
||||
tools:ignore="FragmentTagUsage" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
tools:text="Trending"
|
||||
/>
|
||||
<ImageView
|
||||
android:tint="?attr/textColor"
|
||||
app:tint="?attr/textColor"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_baseline_arrow_forward_24"
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/player_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/player_holder"
|
||||
android:screenOrientation="landscape"
|
||||
tools:orientation="vertical"
|
||||
>
|
||||
tools:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/subtitle_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/shadow_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/shadow_overlay"
|
||||
android:background="@color/black_overlay"
|
||||
/>
|
||||
android:background="@color/black_overlay" />
|
||||
</FrameLayout>
|
||||
|
||||
<!--
|
||||
|
@ -56,602 +55,566 @@
|
|||
</LinearLayout>
|
||||
-->
|
||||
<RelativeLayout
|
||||
android:id="@+id/player_time_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:id="@+id/timeMenu"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toBottomOf="@+id/topMenuRight"
|
||||
app:layout_constraintBottom_toTopOf="@+id/centerMenu"
|
||||
>
|
||||
app:layout_constraintBottom_toTopOf="@+id/player_center_menu"
|
||||
app:layout_constraintTop_toBottomOf="@+id/topMenuRight">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_time_text_left"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/timeTextLeft"
|
||||
android:gravity="center|start"
|
||||
android:textSize="40sp"
|
||||
android:alpha="0"
|
||||
android:layout_marginStart="100dp"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="10.0"
|
||||
android:textColor="@android:color/white"
|
||||
>
|
||||
|
||||
</TextView>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/timeText"
|
||||
android:gravity="center"
|
||||
android:textSize="30sp"
|
||||
android:alpha="0"
|
||||
android:gravity="center|start"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="10.0"
|
||||
android:textColor="@android:color/white"
|
||||
>
|
||||
android:textSize="40sp">
|
||||
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_time_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/timeTextRight"
|
||||
android:gravity="center|end"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:textSize="40sp"
|
||||
android:gravity="center"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="10.0"
|
||||
android:textColor="@android:color/white"
|
||||
>
|
||||
android:textSize="30sp"
|
||||
tools:text="+100">
|
||||
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_text_right"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:gravity="center|end"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="10.0"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="40sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/player_video_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/video_holder"
|
||||
>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/player_top_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginEnd="80dp"
|
||||
android:id="@+id/player_video_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:gravity="center"
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="35dp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:id="@+id/video_title"
|
||||
tools:text="Hello world"
|
||||
>
|
||||
</TextView>
|
||||
<TextView
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginEnd="80dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="20dp"
|
||||
android:textColor="@color/white"
|
||||
android:id="@+id/video_title_rez"
|
||||
tools:text="1920x1080"
|
||||
app:layout_constraintTop_toBottomOf="@+id/video_title">
|
||||
</TextView>
|
||||
<!--
|
||||
<LinearLayout
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:gravity="end"
|
||||
android:layout_margin="5dp"
|
||||
android:paddingEnd="60dp"
|
||||
android:paddingStart="60dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Hello world" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_video_title_rez"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/topMenuRight"
|
||||
>
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="80dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/player_video_title"
|
||||
tools:text="1920x1080" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/next_episode_btt"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="15dp"
|
||||
card_view:cardCornerRadius="2dp"
|
||||
android:foreground="@drawable/outline_card"
|
||||
card_view:cardBackgroundColor="@color/black_overlay"
|
||||
card_view:cardElevation="0dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/next_episode"
|
||||
android:gravity="start|center"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
>
|
||||
</TextView>
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/exo_controls_next"
|
||||
android:layout_gravity="right|center"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingStart="10dp"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
</ImageView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>-->
|
||||
|
||||
|
||||
<androidx.mediarouter.app.MediaRouteButton
|
||||
android:layout_margin="5dp"
|
||||
android:layout_gravity="end"
|
||||
<!-- Removed as it has no use anymore-->
|
||||
<!--<androidx.mediarouter.app.MediaRouteButton
|
||||
android:id="@+id/player_media_route_button"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="5dp"
|
||||
android:mediaRouteTypes="user"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
app:layout_constraintTop_toTopOf="parent" />-->
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/video_go_back_holder2"
|
||||
android:layout_margin="5dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:id="@+id/player_go_back_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
android:layout_margin="5dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||
app:tint="@android:color/white"
|
||||
>
|
||||
</ImageView>
|
||||
android:contentDescription="@string/go_back_img_des" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/video_go_back"
|
||||
android:id="@+id/player_go_back"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="true"
|
||||
android:background="@drawable/video_tap_button_always_white"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/video_tap_button_always_white">
|
||||
</ImageView>
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/go_back_img_des" />
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
||||
<ProgressBar
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:id="@+id/player_buffering"
|
||||
android:layout_gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" />
|
||||
|
||||
<!-- This nested layout is necessary because of buffering and clicking-->
|
||||
<FrameLayout
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:id="@+id/player_pause_play_holder_holder">
|
||||
|
||||
<FrameLayout
|
||||
tools:ignore="uselessParent"
|
||||
android:id="@+id/player_pause_play_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ImageView
|
||||
app:tint="@color/white"
|
||||
android:id="@+id/player_pause_play"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
|
||||
android:layout_gravity="center"
|
||||
|
||||
android:src="@drawable/netflix_pause"
|
||||
android:background="@drawable/video_tap_button"
|
||||
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/player_center_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/centerMenu"
|
||||
>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<FrameLayout
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="@id/player_pause_holder"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:id="@+id/player_rew_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintWidth_percent="0.5"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_height="wrap_content">
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/player_ffwd_holder"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exo_rew_text"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"
|
||||
tools:text="10"
|
||||
android:textSize="19sp"
|
||||
|
||||
android:layout_gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
tools:text="10" />
|
||||
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="40dp">
|
||||
</TextView>
|
||||
<ImageButton
|
||||
android:nextFocusUp="@id/video_go_back"
|
||||
android:nextFocusDown="@id/lock_player"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
android:tint="@color/white"
|
||||
|
||||
android:paddingLeft="100dp"
|
||||
android:id="@id/exo_rew"
|
||||
android:layout_height="70dp"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:padding="10dp"
|
||||
|
||||
android:background="@drawable/video_tap_button_skip"
|
||||
android:src="@drawable/netflix_skip_forward"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
android:padding="10dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:scaleX="-1"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/netflix_skip_forward"
|
||||
app:tint="@color/white"
|
||||
android:tintMode="src_in"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<!-- style="@style/ExoMediaButton.Play"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
-->
|
||||
<FrameLayout
|
||||
app:layout_constraintLeft_toLeftOf="@id/player_rew_holder"
|
||||
app:layout_constraintRight_toRightOf="@id/player_ffwd_holder"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/player_pause_holder"
|
||||
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp">
|
||||
<ImageButton
|
||||
android:nextFocusUp="@id/video_go_back"
|
||||
android:nextFocusDown="@id/lock_player"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:tint="@color/white"
|
||||
|
||||
android:id="@id/exo_play"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_height="70dp"
|
||||
android:layout_width="70dp"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/netflix_play"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
/>
|
||||
<ImageButton
|
||||
android:nextFocusUp="@id/video_go_back"
|
||||
android:nextFocusDown="@id/lock_player"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:id="@id/exo_pause"
|
||||
android:tint="@color/white"
|
||||
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_height="70dp"
|
||||
android:layout_width="70dp"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/netflix_pause"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
app:layout_constraintLeft_toLeftOf="@id/player_pause_holder"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:id="@+id/player_ffwd_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
app:layout_constraintWidth_percent="0.5"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_height="wrap_content">
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/player_rew_holder"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
tools:text="10"
|
||||
android:id="@+id/exo_ffwd_text"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="19sp"
|
||||
android:layout_gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="40dp">
|
||||
</TextView>
|
||||
<ImageButton
|
||||
android:nextFocusUp="@id/video_go_back"
|
||||
android:nextFocusDown="@id/lock_player"
|
||||
android:nextFocusRight="@id/exo_rew"
|
||||
android:tint="@color/white"
|
||||
tools:text="10" />
|
||||
|
||||
android:layout_gravity="center"
|
||||
<ImageButton
|
||||
android:id="@id/exo_ffwd"
|
||||
android:layout_height="70dp"
|
||||
android:layout_width="70dp"
|
||||
android:padding="10dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
|
||||
android:background="@drawable/video_tap_button_skip"
|
||||
android:src="@drawable/netflix_skip_forward"
|
||||
android:nextFocusRight="@id/exo_rew"
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
android:padding="10dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/netflix_skip_forward"
|
||||
app:tint="@color/white"
|
||||
android:tintMode="src_in"
|
||||
/>
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginBottom="20dp"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
>
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_prev"
|
||||
style="@style/ExoMediaButton.Previous"
|
||||
android:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"/>
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_repeat_toggle"
|
||||
style="@style/ExoMediaButton"
|
||||
android:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"/>
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_next"
|
||||
style="@style/ExoMediaButton.Next"
|
||||
android:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"/>
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_vr"
|
||||
style="@style/ExoMediaButton.VR"
|
||||
android:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"/>
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_play"
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="0dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_pause"
|
||||
app:tint="?attr/colorPrimaryDark"
|
||||
android:tintMode="src_in"
|
||||
tools:ignore="ContentDescription"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="0dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_player_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:id="@+id/bottom_player_bar">
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_video_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/video_bar"
|
||||
>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
tools:text="15:30"
|
||||
android:layout_marginStart="20dp"
|
||||
android:id="@id/exo_position"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="end"
|
||||
android:includeFontPadding="false"
|
||||
android:minWidth="50dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:gravity="end"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="normal"/>
|
||||
android:textStyle="normal"
|
||||
tools:text="15:30" />
|
||||
<!--app:buffered_color="@color/videoCache"-->
|
||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
||||
android:id="@id/exo_progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_weight="1"
|
||||
app:scrubber_enabled_size="24dp"
|
||||
app:scrubber_dragged_size="26dp"
|
||||
|
||||
app:scrubber_color="?attr/colorPrimary"
|
||||
app:bar_height="2dp"
|
||||
app:played_color="?attr/colorPrimary"
|
||||
app:unplayed_color="@color/videoProgress"/>
|
||||
|
||||
app:scrubber_color="?attr/colorPrimary"
|
||||
app:scrubber_dragged_size="26dp"
|
||||
app:scrubber_enabled_size="24dp"
|
||||
app:unplayed_color="@color/videoProgress" />
|
||||
|
||||
<!-- exo_duration-->
|
||||
<TextView
|
||||
tools:text="23:20"
|
||||
android:id="@id/exo_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:includeFontPadding="false"
|
||||
android:minWidth="50dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="normal"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
tools:text="23:20" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="60dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/skip_episode"
|
||||
android:nextFocusRight="@id/resize_player"
|
||||
android:id="@+id/lock_player"
|
||||
app:iconSize="30dp"
|
||||
android:id="@+id/player_lock"
|
||||
style="@style/VideoButton"
|
||||
android:nextFocusLeft="@id/player_skip_episode"
|
||||
android:nextFocusRight="@id/player_resize_btt"
|
||||
android:text="@string/video_lock"
|
||||
app:icon="@drawable/video_locked"
|
||||
|
||||
style="@style/VideoButton"/>
|
||||
app:iconSize="30dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/lock_holder"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/player_lock_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/lock_player"
|
||||
android:nextFocusRight="@id/playback_speed_btt"
|
||||
android:id="@+id/resize_player"
|
||||
|
||||
android:text="@string/video_aspect_ratio_resize"
|
||||
app:icon="@drawable/ic_baseline_aspect_ratio_24"
|
||||
style="@style/VideoButton"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/resize_player"
|
||||
android:nextFocusRight="@id/sources_btt"
|
||||
android:id="@+id/playback_speed_btt"
|
||||
|
||||
tools:text="Speed"
|
||||
app:icon="@drawable/ic_baseline_speed_24"
|
||||
style="@style/VideoButton"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/playback_speed_btt"
|
||||
android:nextFocusRight="@id/skip_op"
|
||||
android:id="@+id/sources_btt"
|
||||
|
||||
android:text="@string/video_source"
|
||||
app:icon="@drawable/ic_baseline_playlist_play_24"
|
||||
style="@style/VideoButton"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/sources_btt"
|
||||
android:nextFocusRight="@id/skip_episode"
|
||||
android:id="@+id/skip_op"
|
||||
|
||||
android:text="@string/video_skip_op"
|
||||
app:icon="@drawable/ic_baseline_fast_forward_24"
|
||||
style="@style/VideoButton"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/skip_op"
|
||||
android:nextFocusRight="@id/lock_player"
|
||||
android:id="@+id/skip_episode"
|
||||
|
||||
android:text="@string/next_episode"
|
||||
app:icon="@drawable/ic_baseline_skip_next_24"
|
||||
android:id="@+id/player_resize_btt"
|
||||
style="@style/VideoButton"
|
||||
/>
|
||||
android:nextFocusLeft="@id/player_lock"
|
||||
|
||||
android:nextFocusRight="@id/playback_speed_btt"
|
||||
android:text="@string/video_aspect_ratio_resize"
|
||||
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/playback_speed_btt"
|
||||
style="@style/VideoButton"
|
||||
android:nextFocusLeft="@id/player_resize_btt"
|
||||
|
||||
android:nextFocusRight="@id/player_sources_btt"
|
||||
app:icon="@drawable/ic_baseline_speed_24"
|
||||
tools:text="Speed" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/player_sources_btt"
|
||||
style="@style/VideoButton"
|
||||
android:nextFocusLeft="@id/playback_speed_btt"
|
||||
|
||||
android:nextFocusRight="@id/player_skip_op"
|
||||
android:text="@string/video_source"
|
||||
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/player_skip_op"
|
||||
style="@style/VideoButton"
|
||||
android:nextFocusLeft="@id/player_sources_btt"
|
||||
|
||||
android:nextFocusRight="@id/player_skip_episode"
|
||||
android:text="@string/video_skip_op"
|
||||
app:icon="@drawable/ic_baseline_fast_forward_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/player_skip_episode"
|
||||
style="@style/VideoButton"
|
||||
android:nextFocusLeft="@id/player_skip_op"
|
||||
|
||||
android:nextFocusRight="@id/player_lock"
|
||||
android:text="@string/next_episode"
|
||||
app:icon="@drawable/ic_baseline_skip_next_24" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<View
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/brightness_overlay"
|
||||
android:background="@android:color/black"
|
||||
android:alpha="0"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/click_overlay"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/player_progressbar_left_holder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="left"
|
||||
tools:alpha="1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:gravity="start"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/centerMenuView"
|
||||
android:id="@+id/progressBarLeftHolder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0"
|
||||
>
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:alpha="1"
|
||||
tools:visibility="visible">
|
||||
<!--VERY hacky layout -->
|
||||
<ImageView
|
||||
android:layout_marginBottom="220dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:id="@+id/player_progressbar_left_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="220dp"
|
||||
android:src="@drawable/ic_baseline_volume_up_24"
|
||||
app:tint="@android:color/white"
|
||||
>
|
||||
tools:ignore="ContentDescription">
|
||||
|
||||
</ImageView>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:id="@+id/player_progressbar_left"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="4dp"
|
||||
android:layout_height="150dp"
|
||||
android:id="@+id/progressBarLeft"
|
||||
android:indeterminate="false"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:max="100"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:progress="100"
|
||||
android:progressDrawable="@drawable/progress_drawable_vertical"
|
||||
/>
|
||||
tools:progress="30" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="right"
|
||||
tools:alpha="1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@+id/centerMenuView"
|
||||
android:id="@+id/progressBarRightHolder"
|
||||
android:id="@+id/player_progressbar_right_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0"
|
||||
tools:ignore="RtlHardcoded">
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="right"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@+id/centerMenuView"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:alpha="1"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_marginBottom="220dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:id="@+id/player_progressbar_right_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="220dp"
|
||||
android:src="@drawable/ic_baseline_brightness_7_24"
|
||||
app:tint="@android:color/white"
|
||||
>
|
||||
tools:ignore="ContentDescription">
|
||||
|
||||
</ImageView>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:id="@+id/player_progressbar_right"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="4dp"
|
||||
android:layout_height="150dp"
|
||||
android:id="@+id/progressBarRight"
|
||||
android:indeterminate="false"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:max="100"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:progress="100"
|
||||
android:progressDrawable="@drawable/progress_drawable_vertical"
|
||||
>
|
||||
</ProgressBar>
|
||||
android:progressDrawable="@drawable/progress_drawable_vertical" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
|
|
@ -1,150 +1,129 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@null"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="60dp"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
android:background="@null"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="60dp"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sort_sources_holder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="50"
|
||||
android:orientation="vertical">
|
||||
android:id="@+id/sort_sources_holder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="50"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_marginTop="10dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingBottom="10dp"
|
||||
android:text="@string/pick_source"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/sort_providers"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
android:layout_height="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:nextFocusLeft="@id/sort_subtitles"
|
||||
android:nextFocusRight="@id/apply_btt"
|
||||
tools:listitem="@layout/sort_bottom_single_choice" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sort_subtitles_holder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="50"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/subs_settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
|
||||
android:layout_weight="1"
|
||||
android:nextFocusRight="@id/sort_providers"
|
||||
|
||||
android:nextFocusDown="@id/sort_subtitles"
|
||||
android:layout_marginTop="10dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:text="@string/pick_subtitle"
|
||||
android:paddingBottom="10dp"
|
||||
android:text="@string/pick_source"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
<ListView
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:id="@+id/sort_providers"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
android:contentDescription="@string/home_change_provider_img_des"
|
||||
android:src="@drawable/ic_outline_settings_24"
|
||||
android:visibility="gone" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:nextFocusLeft="@id/sort_subtitles"
|
||||
android:nextFocusRight="@id/apply_btt"
|
||||
tools:listitem="@layout/sort_bottom_single_choice" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sort_subtitles_holder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="50"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- android:id="@+id/subs_settings" android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
-->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_marginTop="10dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingBottom="10dp"
|
||||
android:text="@string/pick_subtitle"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
|
||||
android:contentDescription="@string/home_change_provider_img_des"
|
||||
android:src="@drawable/ic_outline_settings_24"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/sort_subtitles"
|
||||
android:layout_width="match_parent"
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:id="@+id/sort_subtitles"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
android:layout_height="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:nextFocusLeft="@id/sort_providers"
|
||||
android:nextFocusRight="@id/cancel_btt"
|
||||
tools:listitem="@layout/sort_bottom_single_choice" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:nextFocusLeft="@id/sort_providers"
|
||||
android:nextFocusRight="@id/cancel_btt"
|
||||
tools:listfooter="@layout/sort_bottom_footer_add_choice"
|
||||
tools:listitem="@layout/sort_bottom_single_choice" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginTop="-60dp"
|
||||
android:orientation="horizontal">
|
||||
android:id="@+id/apply_btt_holder"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="bottom|end"
|
||||
android:layout_marginTop="-60dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp">
|
||||
|
||||
<!-- Kinda hack because the gravity won't behave correctly-->
|
||||
<LinearLayout
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|start">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/load_btt"
|
||||
app:icon="@drawable/ic_baseline_subtitles_24"
|
||||
<com.google.android.material.button.MaterialButton
|
||||
style="@style/WhiteButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:nextFocusLeft="@id/cancel_btt"
|
||||
android:nextFocusRight="@id/apply_btt"
|
||||
android:text="@string/player_load_subtitles" />
|
||||
</LinearLayout>
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:text="@string/sort_apply"
|
||||
android:id="@+id/apply_btt"
|
||||
android:layout_width="wrap_content" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/apply_btt"
|
||||
style="@style/WhiteButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:nextFocusLeft="@id/cancel_btt"
|
||||
android:nextFocusRight="@id/cancel_btt"
|
||||
android:text="@string/sort_apply" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/cancel_btt"
|
||||
style="@style/BlackButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:nextFocusLeft="@id/apply_btt"
|
||||
android:nextFocusRight="@id/apply_btt"
|
||||
android:text="@string/sort_cancel" />
|
||||
style="@style/BlackButton"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:text="@string/sort_cancel"
|
||||
android:id="@+id/cancel_btt"
|
||||
android:layout_width="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
|
@ -15,8 +14,7 @@
|
|||
app:cardBackgroundColor="@color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
android:layout_marginBottom="5dp"
|
||||
>
|
||||
android:layout_marginBottom="5dp">
|
||||
<!-- IDK BUT THIS DOES NOT SEAM LIKE A GOOD WAY OF DOING IT -->
|
||||
<!--<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
|
@ -48,14 +46,15 @@
|
|||
android:layout_width="match_parent"
|
||||
tools:progress="50"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_height="5dp">
|
||||
</androidx.core.widget.ContentLoadingProgressBar>
|
||||
android:layout_height="5dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:tint="?attr/textColor"
|
||||
app:tint="?attr/textColor"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -63,15 +62,21 @@
|
|||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:contentDescription="@string/episode_play_img_des"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
/>
|
||||
android:layout_width="wrap_content" />
|
||||
<!--marquee_forever-->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="center"
|
||||
style="@style/SmallBlackButton"
|
||||
android:text="@string/filler"
|
||||
android:id="@+id/episode_filler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/episode_text"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical" tools:text="Episode 1"
|
||||
android:gravity="center_vertical"
|
||||
tools:text="Episode 1"
|
||||
android:textColor="?attr/textColor"
|
||||
|
||||
android:scrollHorizontally="true"
|
||||
|
@ -81,14 +86,14 @@
|
|||
android:singleLine="true"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</TextView>
|
||||
android:layout_height="match_parent" />
|
||||
</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"
|
||||
|
@ -103,13 +108,13 @@
|
|||
android:layout_margin="5dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:progress="0"
|
||||
android:visibility="visible"
|
||||
/>
|
||||
android:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:nextFocusLeft="@id/episode_holder"
|
||||
android:nextFocusRight="@id/episode_holder"
|
||||
|
||||
android:tint="?attr/white"
|
||||
app:tint="?attr/white"
|
||||
|
||||
android:id="@+id/result_episode_download"
|
||||
android:visibility="visible"
|
||||
|
@ -121,6 +126,6 @@
|
|||
android:layout_width="30dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:contentDescription="@string/download"/>
|
||||
android:contentDescription="@string/download" />
|
||||
</FrameLayout>
|
||||
</androidx.cardview.widget.CardView>
|
|
@ -71,14 +71,28 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/episode_text"
|
||||
tools:text="1. Jobless"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/textColor"
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="start"
|
||||
style="@style/SmallBlackButton"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/filler"
|
||||
android:id="@+id/episode_filler" />
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:id="@+id/episode_text"
|
||||
tools:text="1. Jobless"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/episode_rating"
|
||||
tools:text="Rated: 8.8"
|
||||
|
@ -113,8 +127,6 @@
|
|||
android:nextFocusRight="@id/episode_holder"
|
||||
android:id="@+id/result_episode_download"
|
||||
|
||||
android:tint="?attr/white"
|
||||
|
||||
android:visibility="visible"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -124,7 +136,8 @@
|
|||
android:layout_width="30dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:contentDescription="@string/download"/>
|
||||
android:contentDescription="@string/download"
|
||||
app:tint="?attr/white" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
|
|
23
app/src/main/res/layout/sort_bottom_footer_add_choice.xml
Normal file
23
app/src/main/res/layout/sort_bottom_footer_add_choice.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/AppTextViewStyle"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@color/text_selection_color"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="7dip"
|
||||
tools:text="TEST"
|
||||
android:checkMark="?android:attr/listChoiceIndicatorSingle"
|
||||
android:ellipsize="marquee"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
tools:drawableTint="?attr/textColor"
|
||||
android:drawablePadding="20dp"
|
||||
app:drawableTint="?attr/textColor"
|
||||
app:drawableStartCompat="@drawable/ic_baseline_add_24" />
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/AppTextViewStyle"
|
||||
android:id="@android:id/text1"
|
||||
|
@ -32,8 +33,7 @@
|
|||
android:checkMark="?android:attr/listChoiceIndicatorSingle"
|
||||
android:ellipsize="marquee"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:drawableStart="@drawable/ic_baseline_check_24"
|
||||
android:drawableTint="@color/check_selection_color"
|
||||
tools:drawableTint="?attr/textColor"
|
||||
android:drawablePadding="20dp"
|
||||
/>
|
||||
app:drawableTint="@color/check_selection_color"
|
||||
app:drawableStartCompat="@drawable/ic_baseline_check_24" />
|
||||
|
|
|
@ -188,5 +188,5 @@
|
|||
<fragment
|
||||
android:id="@+id/navigation_player"
|
||||
android:layout_height="match_parent"
|
||||
android:name="com.lagradost.cloudstream3.ui.player.PlayerFragment"/>
|
||||
android:name="com.lagradost.cloudstream3.ui.player.GeneratorPlayer"/>
|
||||
</navigation>
|
|
@ -13,7 +13,6 @@
|
|||
<string name="player_speed_text_format" formatted="true">سرعة (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">!تم إيجاد تحديث جديد\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">الصفحة الرئيسية</string>
|
||||
|
@ -43,7 +42,7 @@
|
|||
<string name="pick_source">المصادر</string>
|
||||
<string name="pick_subtitle">الترجمة</string>
|
||||
<string name="reload_error">…إعادة محاولة الاتصال</string>
|
||||
<string name="result_go_back">ارجع للخلف</string>
|
||||
<string name="go_back">ارجع للخلف</string>
|
||||
<string name="play_episode">تشغيل الحلقة</string>
|
||||
<!--<string name="need_storage">السماح بتحميل الحلقات</string>-->
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
<string name="player_speed_text_format" formatted="true">Geschwindigkeit (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Bewertung: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Neues Update gefunden!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Startseite</string>
|
||||
<string name="title_search">Suchen</string>
|
||||
|
@ -37,7 +36,7 @@
|
|||
<string name="pick_source">Quellen</string>
|
||||
<string name="pick_subtitle">Untertitel</string>
|
||||
<string name="reload_error">Verbindung wiederholen…</string>
|
||||
<string name="result_go_back">Zurück</string>
|
||||
<string name="go_back">Zurück</string>
|
||||
<string name="play_episode">Episode abspielen</string>
|
||||
<string name="download">Herunterladen</string>
|
||||
<string name="downloaded">Heruntergeladen</string>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Velocidad (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Puntuado: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">¡Nueva actualización encontrada!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Relleno) %s</string>
|
||||
<string name="filler" formatted="true">Relleno</string>
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Inicio</string>
|
||||
<string name="title_search">Buscar</string>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<string name="pick_source">Fuentes</string>
|
||||
<string name="pick_subtitle">Subtítulos</string>
|
||||
<string name="reload_error">Reintentar conexión…</string>
|
||||
<string name="result_go_back">Ir atrás</string>
|
||||
<string name="go_back">Ir atrás</string>
|
||||
<string name="play_episode">Reproducir capítulo</string>
|
||||
<string name="download">Descarga</string>
|
||||
<string name="downloaded">Descargada</string>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<string name="pick_source">Sources</string>
|
||||
<string name="pick_subtitle">Sous-titres</string>
|
||||
<string name="reload_error">Réessayer la connection…</string>
|
||||
<string name="result_go_back">Retour</string>
|
||||
<string name="go_back">Retour</string>
|
||||
<string name="episode_poster_img_des">Miniature de l\'Episode</string>
|
||||
<string name="play_episode">Lire l\'Episode</string>
|
||||
<string name="need_storage">Permet de télécharger les épisodes</string>
|
||||
|
@ -178,7 +178,7 @@
|
|||
<string name="dns_pref_summary">Utile pour contourner les bloquages des FAI</string>
|
||||
<string name="new_update_format" formatted="true">Nouvelle mise à jour trouvée !
|
||||
\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Épisode spécial) %s</string>
|
||||
<string name="filler" formatted="true">Épisode spécial</string>
|
||||
<string name="watch_quality_pref">Qualité de visionnage préférée</string>
|
||||
<string name="resize_fill">Étendre</string>
|
||||
<string name="legal_notice">Non-responsabilité</string>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<string name="pick_source">Πηγές</string>
|
||||
<string name="pick_subtitle">Υπότιτλοι</string>
|
||||
<string name="reload_error">Ξανά φόρτωσε…</string>
|
||||
<string name="result_go_back">Πίσω</string>
|
||||
<string name="go_back">Πίσω</string>
|
||||
<string name="episode_poster_img_des">Πόστερ</string>
|
||||
<string name="play_episode">Αναπαραγωγή Επισοδείου</string>
|
||||
<string name="need_storage">Δώσε άδεια για την λήψη επισοδείου</string>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<string name="play_torrent_button">टोरेंट चलाये</string>
|
||||
<string name="pick_source">सूत्र</string>
|
||||
<string name="reload_error">फिरसे प्रयास करे…</string>
|
||||
<string name="result_go_back">वापिस जाए</string>
|
||||
<string name="go_back">वापिस जाए</string>
|
||||
<string name="play_episode">एपिसोड चलाये</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Брзина (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Оценето: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Пронајдена нова верзија на апликацијата!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Филтер) %s</string>
|
||||
<string name="filler" formatted="true">Филтер</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Дома</string>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<string name="pick_source">Извори</string>
|
||||
<string name="pick_subtitle">Преводи</string>
|
||||
<string name="reload_error">Повтори конекција…</string>
|
||||
<string name="result_go_back">Оди назад</string>
|
||||
<string name="go_back">Оди назад</string>
|
||||
<string name="play_episode">Пушти епизода</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<string name="pick_source">സ്രോതസുകൾ</string>
|
||||
<string name="pick_subtitle">സബ്ടൈറ്റിലുകൾ</string>
|
||||
<string name="reload_error">വീണ്ടും കണക്ട് ചെയ്യുക…</string>
|
||||
<string name="result_go_back">പിന്നോട്ട് പോകുക</string>
|
||||
<string name="go_back">പിന്നോട്ട് പോകുക</string>
|
||||
<string name="play_episode">എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക</string>
|
||||
|
||||
<string name="download">ഡൌൺലോഡ്</string>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<string name="pick_source">oha aauuh</string>
|
||||
<string name="pick_subtitle">ahooo ooo-ahah</string>
|
||||
<string name="reload_error">aaaghhahaaaaaaaaaaooh</string>
|
||||
<string name="result_go_back">aauugghhaaaghh</string>
|
||||
<string name="go_back">aauugghhaaaghh</string>
|
||||
<string name="episode_poster_img_des">oouuhahoooooo-ahahoooohh</string>
|
||||
<string name="play_episode">aaaaa oh ohaouuhhh</string>
|
||||
<string name="need_storage">ahouuhhhaaaaa ahhaaaghh ahhh</string>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<string name="pick_source">Bronnen</string>
|
||||
<string name="pick_subtitle">Ondertitels</string>
|
||||
<string name="reload_error">Probeer verbinding opnieuw…</string>
|
||||
<string name="result_go_back">Ga terug</string>
|
||||
<string name="go_back">Ga terug</string>
|
||||
<string name="episode_poster_img_des">Afleveringsposter</string>
|
||||
<string name="play_episode">Aflevering afspelen</string>
|
||||
<string name="need_storage">Toestaan om afleveringen te downloaden</string>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<string name="player_speed_text_format" formatted="true">Avspillingshastighet (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Vurdert: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Ny oppdatering funnet!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Hjem</string>
|
||||
|
@ -43,7 +42,7 @@
|
|||
<string name="pick_source">Kilder</string>
|
||||
<string name="pick_subtitle">Undertekster</string>
|
||||
<string name="reload_error">Prøv tilkoblingen på nytt…</string>
|
||||
<string name="result_go_back">Gå tilbake</string>
|
||||
<string name="go_back">Gå tilbake</string>
|
||||
<string name="play_episode">Spille Episode</string>
|
||||
<!--<string name="need_storage">Tillat å laste ned episoder</string>-->
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<string name="pick_source">Źródła</string>
|
||||
<string name="pick_subtitle">Napisy</string>
|
||||
<string name="reload_error">Połącz ponownie…</string>
|
||||
<string name="result_go_back">Wstecz</string>
|
||||
<string name="go_back">Wstecz</string>
|
||||
<string name="play_episode">Odtwórz odcinek</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
@ -223,7 +223,7 @@
|
|||
<string name="home_main_poster_img_des">Główny plakat</string>
|
||||
<string name="home_next_random_img_des">Następny losowy</string>
|
||||
<string name="go_back_img_des">Wstecz</string>
|
||||
<string name="filler_format">(WYpełniacz) %s</string>
|
||||
<string name="filler">WYpełniacz</string>
|
||||
<string name="home_change_provider_img_des">Zmień dostawcę</string>
|
||||
<string name="preview_background_img_des">Pogląd tła</string>
|
||||
</resources>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Velocidade (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Classificado: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Nova atualização encontrada!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Cheio) %s</string>
|
||||
<string name="filler" formatted="true">Cheio</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Início</string>
|
||||
|
@ -46,7 +46,7 @@
|
|||
<string name="pick_source">Origems</string>
|
||||
<string name="pick_subtitle">Subtítulos</string>
|
||||
<string name="reload_error">Reintentar conexão…</string>
|
||||
<string name="result_go_back">Voltar Atrás</string>
|
||||
<string name="go_back">Voltar Atrás</string>
|
||||
<string name="play_episode">Assistir Episódio</string>
|
||||
|
||||
<string name="download">Descàrregar</string>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Viteză (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Evaluat: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Noua actualizare găsită!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Umplut) %s</string>
|
||||
<string name="filler" formatted="true">Umplut</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Principal</string>
|
||||
|
@ -46,7 +46,7 @@
|
|||
<string name="pick_source">Surse</string>
|
||||
<string name="pick_subtitle">Subtitrare</string>
|
||||
<string name="reload_error">Reîncercarea conexiunii…</string>
|
||||
<string name="result_go_back">Întoarce-te</string>
|
||||
<string name="go_back">Întoarce-te</string>
|
||||
<string name="play_episode">Redă episodul</string>
|
||||
|
||||
<string name="download">Descărcare</string>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<string name="pick_source">Källor</string>
|
||||
<string name="pick_subtitle">Undertexter</string>
|
||||
<string name="reload_error">Försök ansluta igen…</string>
|
||||
<string name="result_go_back">Gå tillbaka</string>
|
||||
<string name="go_back">Gå tillbaka</string>
|
||||
<string name="episode_poster_img_des">@string/result_poster_img_des</string>
|
||||
<string name="play_episode">Spela Avsnitt</string>
|
||||
<string name="download">Ladda ner</string>
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
<string name="player_speed_text_format" formatted="true">Bilis (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Bagong update!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Home</string>
|
||||
|
@ -50,7 +49,7 @@
|
|||
<string name="pick_source">Sources</string>
|
||||
<string name="pick_subtitle">Subtitles</string>
|
||||
<string name="reload_error">Retry connection…</string>
|
||||
<string name="result_go_back">Go back</string>
|
||||
<string name="go_back">Go back</string>
|
||||
<string name="play_episode">I-play ang episode</string>
|
||||
<!--<string name="need_storage">Payagan sa Itabi</string>-->
|
||||
|
||||
|
|
|
@ -31,18 +31,6 @@
|
|||
<string name="prefer_media_type_key" translatable="false">prefer_media_type_key</string>
|
||||
<string name="app_theme_key" translatable="false">app_theme_key</string>
|
||||
|
||||
|
||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
|
||||
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
|
||||
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
|
||||
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
|
||||
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
|
||||
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
|
||||
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
|
||||
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
|
||||
<string name="app_dub_sub_episode_text_format">%s Ep %d</string>
|
||||
|
||||
<!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->
|
||||
<string name="result_poster_img_des">Afiş</string>
|
||||
<string name="search_poster_img_des">@string/result_poster_img_des</string>
|
||||
|
@ -59,7 +47,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Hız (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Puan: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">Yeni güncelleme bulundu!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Doldurucu) %s</string>
|
||||
<string name="filler" formatted="true">Doldurucu</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
<string name="title_home">Ana Sayfa</string>
|
||||
|
@ -89,7 +77,7 @@
|
|||
<string name="pick_source">Kaynaklar</string>
|
||||
<string name="pick_subtitle">Altyazılar</string>
|
||||
<string name="reload_error">Yeniden bağlanmayı dene…</string>
|
||||
<string name="result_go_back">Geri Git</string>
|
||||
<string name="go_back">Geri Git</string>
|
||||
<string name="play_episode">Bölümü Oynat</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<string name="pick_source">Nguồn Phim</string>
|
||||
<string name="pick_subtitle">Phụ Đề</string>
|
||||
<string name="reload_error">Thử kết nối lại…</string>
|
||||
<string name="result_go_back">Quay lại</string>
|
||||
<string name="go_back">Quay lại</string>
|
||||
<string name="play_episode">Xem Tập Phim</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
<item>Apple</item>
|
||||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink Pain</item>
|
||||
</string-array>
|
||||
<string-array name="themes_overlay_names_values">
|
||||
<item>Normal</item>
|
||||
|
@ -111,6 +112,7 @@
|
|||
<item>GreenApple</item>
|
||||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="themes_names">
|
||||
|
|
|
@ -62,4 +62,5 @@
|
|||
<color name="colorPrimaryGreenApple">#48E484</color>
|
||||
<color name="colorPrimaryBanana">#E4D448</color>
|
||||
<color name="colorPrimaryParty">#ea596e</color>
|
||||
<color name="colorPrimaryPink">#ff1493</color>
|
||||
</resources>
|
|
@ -19,6 +19,7 @@
|
|||
<string name="player_resize_enabled_key" translatable="false">player_resize_enabled_key</string>
|
||||
<string name="pip_enabled_key" translatable="false">pip_enabled_key</string>
|
||||
<string name="double_tap_enabled_key" translatable="false">double_tap_enabled_key</string>
|
||||
<string name="double_tap_pause_enabled_key" translatable="false">double_tap_pause_enabled_key</string>
|
||||
<string name="swipe_vertical_enabled_key" translatable="false">swipe_vertical_enabled_key</string>
|
||||
<string name="display_sub_key" translatable="false">display_sub_key</string>
|
||||
<string name="show_fillers_key" translatable="false">show_fillers_key</string>
|
||||
|
@ -61,7 +62,7 @@
|
|||
<string name="player_speed_text_format" formatted="true">Speed (%.2fx)</string>
|
||||
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
||||
<string name="new_update_format" formatted="true">New update found!\n%s -> %s</string>
|
||||
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||
<string name="filler" formatted="true">Filler</string>
|
||||
<string name="duration_format" formatted="true">%d min</string>
|
||||
|
||||
<string name="app_name">CloudStream</string>
|
||||
|
@ -94,7 +95,7 @@
|
|||
<string name="pick_source">Sources</string>
|
||||
<string name="pick_subtitle">Subtitles</string>
|
||||
<string name="reload_error">Retry connection…</string>
|
||||
<string name="result_go_back">Go Back</string>
|
||||
<string name="go_back">Go Back</string>
|
||||
<string name="play_episode">Play Episode</string>
|
||||
<!--<string name="need_storage">Allow to download episodes</string>-->
|
||||
|
||||
|
@ -178,8 +179,10 @@
|
|||
<string name="swipe_to_change_settings">Swipe to change settings</string>
|
||||
<string name="swipe_to_change_settings_des">Swipe on the left or right side to change brightness or volume</string>
|
||||
<string name="double_tap_to_seek_settings">Double tap to seek</string>
|
||||
<string name="double_tap_to_pause_settings">Double tap to pause</string>
|
||||
<string name="double_tap_to_seek_settings_des">Tap twice on the right or left side to seek forwards or backwards
|
||||
</string>
|
||||
<string name="double_tap_to_pause_settings_des">Tap in the middle to pause</string>
|
||||
<string name="use_system_brightness_settings">Use system brightness</string>
|
||||
<string name="use_system_brightness_settings_des">Use system brightness in the app player instead of a dark
|
||||
overlay
|
||||
|
@ -226,6 +229,8 @@
|
|||
<string name="cancel" translatable="false">@string/sort_cancel</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="resume">Resume</string>
|
||||
<string name="go_back_30">-30</string>
|
||||
<string name="go_forward_30">+30</string>
|
||||
<string name="delete_message" formatted="true">This will permanently delete %s\nAre you sure?</string>
|
||||
|
||||
<string name="status_ongoing">Ongoing</string>
|
||||
|
@ -368,6 +373,7 @@
|
|||
<string name="subtitles_example_text">The quick brown fox jumps over the lazy dog</string>
|
||||
|
||||
<string name="tab_recommended">Recommended</string>
|
||||
<string name="player_loaded_subtitles">Loaded %s</string>
|
||||
<string name="player_loaded_subtitles" formatted="true">Loaded %s</string>
|
||||
<string name="player_load_subtitles">Load from file</string>
|
||||
<string name="downloaded_file">Downloaded file</string>
|
||||
</resources>
|
||||
|
|
|
@ -165,6 +165,15 @@
|
|||
<item name="android:colorAccent">@color/colorPrimaryParty</item>
|
||||
</style>
|
||||
|
||||
<style name="OverlayPrimaryColorPink">
|
||||
<item name="colorPrimary">@color/colorPrimaryPink</item>
|
||||
<item name="android:colorPrimary">@color/colorPrimaryPink</item>
|
||||
<item name="colorPrimaryDark">#DD1280</item>
|
||||
<item name="colorAccent">#FF4DAE</item>
|
||||
<item name="colorOnPrimary">#DD1280</item>
|
||||
<item name="android:colorAccent">@color/colorPrimaryPink</item>
|
||||
</style>
|
||||
|
||||
<style name="LoadedStyle">
|
||||
<item name="android:navigationBarColor">?attr/primaryGrayBackground</item>
|
||||
<item name="android:windowBackground">?attr/primaryBlackBackground</item>
|
||||
|
@ -323,6 +332,19 @@
|
|||
<item name="rippleColor">?attr/textColor</item>
|
||||
</style>
|
||||
|
||||
<style name="SmallBlackButton" parent="BlackButton">
|
||||
<item name="android:layout_height">24dp</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:layout_marginStart">0dp</item>
|
||||
<item name="android:layout_marginEnd">0dp</item>
|
||||
<item name="android:stateListAnimator">@null</item>
|
||||
<item name="iconPadding">0dp</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
<item name="android:paddingBottom">0dp</item>
|
||||
<item name="android:minWidth">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RoundedSelectableButtonIcon" parent="RoundedSelectableButton">
|
||||
<item name="minWidth">0dp</item>
|
||||
<item name="iconTint">?attr/textColor</item>
|
||||
|
|
|
@ -60,6 +60,14 @@
|
|||
android:summary="@string/double_tap_to_seek_settings_des"
|
||||
app:defaultValue="false"
|
||||
/>
|
||||
<SwitchPreference
|
||||
android:icon="@drawable/netflix_pause"
|
||||
app:key="@string/double_tap_pause_enabled_key"
|
||||
android:title="@string/double_tap_to_pause_settings"
|
||||
android:summary="@string/double_tap_to_pause_settings_des"
|
||||
app:defaultValue="false"
|
||||
/>
|
||||
<!--
|
||||
<SwitchPreference
|
||||
android:icon="@drawable/ic_baseline_brightness_7_24"
|
||||
app:key="@string/use_system_brightness_key"
|
||||
|
@ -67,6 +75,7 @@
|
|||
android:summary="@string/use_system_brightness_settings_des"
|
||||
app:defaultValue="false"
|
||||
/>
|
||||
-->
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="general"
|
||||
|
|
Loading…
Reference in a new issue