forked from recloudstream/cloudstream
		
	Player v2 (#401)
This commit is contained in:
		
							parent
							
								
									cb65299e57
								
							
						
					
					
						commit
						9fd237301e
					
				
					 94 changed files with 5997 additions and 4025 deletions
				
			
		
							
								
								
									
										12
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -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:usesCleartextTraffic="true" | ||||||
|             android:roundIcon="@mipmap/ic_launcher_round" |             android:roundIcon="@mipmap/ic_launcher_round" | ||||||
|             android:supportsRtl="true" |             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 |         <meta-data | ||||||
|                 android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" |                 android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" | ||||||
|                 android:value="com.lagradost.cloudstream3.utils.CastOptionsProvider"/> |                 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 |         <activity | ||||||
|                 android:exported="true" |                 android:exported="true" | ||||||
|                 android:name=".MainActivity" |                 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.fasterxml.jackson.module.kotlin.KotlinModule | ||||||
| import com.lagradost.cloudstream3.animeproviders.* | import com.lagradost.cloudstream3.animeproviders.* | ||||||
| import com.lagradost.cloudstream3.movieproviders.* | import com.lagradost.cloudstream3.movieproviders.* | ||||||
|  | import com.lagradost.cloudstream3.ui.player.SubtitleData | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import java.util.* | 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 } |     return urls.sortedBy { t -> -t.quality } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun sortSubs(urls: List<SubtitleFile>): List<SubtitleFile> { | fun sortSubs(subs : Set<SubtitleData>) : List<SubtitleData> { | ||||||
|     val encounteredTimes = HashMap<String, Int>() |     return subs.sortedBy { it.name } | ||||||
|     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 capitalizeString(str: String): String { | fun capitalizeString(str: String): String { | ||||||
|  | @ -377,6 +372,11 @@ fun TvType.isMovieType(): Boolean { | ||||||
|     return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent |     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) | data class SubtitleFile(val lang: String, val url: String) | ||||||
| 
 | 
 | ||||||
| class HomePageResponse( | class HomePageResponse( | ||||||
|  | @ -463,7 +463,7 @@ interface LoadResponse { | ||||||
| 
 | 
 | ||||||
| fun LoadResponse?.isEpisodeBased(): Boolean { | fun LoadResponse?.isEpisodeBased(): Boolean { | ||||||
|     if (this == null) return false |     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 { | fun LoadResponse?.isAnimeBased(): Boolean { | ||||||
|  | @ -471,6 +471,11 @@ fun LoadResponse?.isAnimeBased(): Boolean { | ||||||
|     return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse) |     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( | data class AnimeEpisode( | ||||||
|     val url: String, |     val url: String, | ||||||
|     var name: String? = null, |     var name: String? = null, | ||||||
|  |  | ||||||
|  | @ -1,23 +1,13 @@ | ||||||
| package com.lagradost.cloudstream3 | package com.lagradost.cloudstream3 | ||||||
| 
 | 
 | ||||||
| import android.app.Activity |  | ||||||
| import android.app.PictureInPictureParams |  | ||||||
| import android.content.ComponentName | import android.content.ComponentName | ||||||
| import android.content.Context |  | ||||||
| import android.content.Intent | import android.content.Intent | ||||||
| import android.content.pm.PackageManager |  | ||||||
| import android.content.res.ColorStateList | import android.content.res.ColorStateList | ||||||
| import android.content.res.Configuration | import android.content.res.Configuration | ||||||
| import android.content.res.Resources |  | ||||||
| import android.os.Build |  | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import android.view.* | import android.view.KeyEvent | ||||||
| import android.view.KeyEvent.ACTION_DOWN | import android.view.WindowManager | ||||||
| import android.widget.TextView |  | ||||||
| import android.widget.Toast |  | ||||||
| import androidx.annotation.StringRes |  | ||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
| import androidx.appcompat.widget.SearchView |  | ||||||
| import androidx.core.view.isVisible | import androidx.core.view.isVisible | ||||||
| import androidx.navigation.NavDestination | import androidx.navigation.NavDestination | ||||||
| import androidx.navigation.findNavController | 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.apis | ||||||
| import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings | import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings | ||||||
| import com.lagradost.cloudstream3.APIHolder.restrictedApis | 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.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.network.Requests | import com.lagradost.cloudstream3.network.Requests | ||||||
| import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver | 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.syncproviders.OAuth2API.Companion.appString | ||||||
| import com.lagradost.cloudstream3.ui.APIRepository | import com.lagradost.cloudstream3.ui.APIRepository | ||||||
| import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO | 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.ui.settings.SettingsFragment.Companion.isTvSettings | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable | 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.AppUtils.loadResult | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.removeKey | import com.lagradost.cloudstream3.utils.DataStore.removeKey | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos | 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.InAppUpdater.Companion.runAutoUpdate | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.checkWrite | import com.lagradost.cloudstream3.utils.UIHelper.checkWrite | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor | 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.hideKeyboard | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.navigate | import com.lagradost.cloudstream3.utils.UIHelper.navigate | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.requestRW | 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.activity_main.* | ||||||
| import kotlinx.android.synthetic.main.fragment_result.* | import kotlinx.android.synthetic.main.fragment_result.* | ||||||
| import java.util.* | import java.io.File | ||||||
| import kotlin.concurrent.thread | 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_POSITION_OUT = "extra_position" | ||||||
| const val VLC_EXTRA_DURATION_OUT = "extra_duration" | const val VLC_EXTRA_DURATION_OUT = "extra_duration" | ||||||
| const val VLC_LAST_ID_KEY = "vlc_last_open_id" | const val VLC_LAST_ID_KEY = "vlc_last_open_id" | ||||||
|  | 
 | ||||||
| // Short name for requests client to make it nicer to use | // Short name for requests client to make it nicer to use | ||||||
| var app = Requests() | var app = Requests() | ||||||
| 
 | 
 | ||||||
|  | @ -91,7 +83,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|         findNavController(R.id.nav_host_fragment).currentDestination?.let { updateNavBar(it) } |         findNavController(R.id.nav_host_fragment).currentDestination?.let { updateNavBar(it) } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun updateNavBar(destination : NavDestination) { |     private fun updateNavBar(destination: NavDestination) { | ||||||
|         this.hideKeyboard() |         this.hideKeyboard() | ||||||
| 
 | 
 | ||||||
|         // Fucks up anime info layout since that has its own layout |         // Fucks up anime info layout since that has its own layout | ||||||
|  | @ -106,7 +98,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|             R.id.navigation_download_child |             R.id.navigation_download_child | ||||||
|         ).contains(destination.id) |         ).contains(destination.id) | ||||||
| 
 | 
 | ||||||
|         val landscape = when(resources.configuration.orientation) { |         val landscape = when (resources.configuration.orientation) { | ||||||
|             Configuration.ORIENTATION_LANDSCAPE -> { |             Configuration.ORIENTATION_LANDSCAPE -> { | ||||||
|                 true |                 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 { |     override fun dispatchKeyEvent(event: KeyEvent?): Boolean { | ||||||
|         event?.keyCode?.let { keyCode -> |         CommonActivity.dispatchKeyEvent(this, event)?.let { | ||||||
|             when (event.action) { |             return it | ||||||
|                 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 |  | ||||||
|         } |         } | ||||||
|         return super.dispatchKeyEvent(event) |         return super.dispatchKeyEvent(event) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { |     override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { | ||||||
|         //println("Keycode: $keyCode") |         CommonActivity.onKeyDown(this, keyCode, event) | ||||||
|         //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") |  | ||||||
|         //    } |  | ||||||
|         //} |  | ||||||
| 
 | 
 | ||||||
|         return super.onKeyDown(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() { |     override fun onUserLeaveHint() { | ||||||
|         super.onUserLeaveHint() |         super.onUserLeaveHint() | ||||||
|         if (canEnterPipMode && canShowPipMode) { |         onUserLeaveHint(this) | ||||||
|             enterPIPMode() |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onBackPressed() { |     override fun onBackPressed() { | ||||||
|  | @ -456,9 +204,15 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|         if (VLC_REQUEST_CODE == requestCode) { |         if (VLC_REQUEST_CODE == requestCode) { | ||||||
|             if (resultCode == RESULT_OK && data != null) { |             if (resultCode == RESULT_OK && data != null) { | ||||||
|                 val pos: Long = |                 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 = |                 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) |                 val id = getKey<Int>(VLC_LAST_ID_KEY) | ||||||
|                 println("SET KEY $id at $pos / $dur") |                 println("SET KEY $id at $pos / $dur") | ||||||
|                 if (dur > 0 && pos > 0) { |                 if (dur > 0 && pos > 0) { | ||||||
|  | @ -486,6 +240,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|     private fun handleAppIntent(intent: Intent?) { |     private fun handleAppIntent(intent: Intent?) { | ||||||
|         if (intent == null) return |         if (intent == null) return | ||||||
|         val str = intent.dataString |         val str = intent.dataString | ||||||
|  |         loadCache() | ||||||
|         if (str != null) { |         if (str != null) { | ||||||
|             if (str.contains(appString)) { |             if (str.contains(appString)) { | ||||||
|                 for (api in OAuth2Apis) { |                 for (api in OAuth2Apis) { | ||||||
|  | @ -513,37 +268,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|         for (api in OAuth2accountApis) { |         for (api in OAuth2accountApis) { | ||||||
|             api.init() |             api.init() | ||||||
|         } |         } | ||||||
| 
 |         loadThemes(this) | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|         updateLocale() |         updateLocale() | ||||||
|         app.initClient(this) |         app.initClient(this) | ||||||
|         super.onCreate(savedInstanceState) |         super.onCreate(savedInstanceState) | ||||||
|  | @ -565,12 +290,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
| 
 | 
 | ||||||
|         //  val navView: BottomNavigationView = findViewById(R.id.nav_view) |         //  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 |         CommonActivity.init(this) | ||||||
|         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 |  | ||||||
| 
 | 
 | ||||||
|         val navController = findNavController(R.id.nav_host_fragment) |         val navController = findNavController(R.id.nav_host_fragment) | ||||||
| 
 | 
 | ||||||
|  | @ -588,6 +309,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|         navController.addOnDestinationChangedListener { _, destination, _ -> |         navController.addOnDestinationChangedListener { _, destination, _ -> | ||||||
|             updateNavBar(destination) |             updateNavBar(destination) | ||||||
|         } |         } | ||||||
|  |         loadCache() | ||||||
| 
 | 
 | ||||||
|         /*nav_view.setOnNavigationItemSelectedListener { item -> |         /*nav_view.setOnNavigationItemSelectedListener { item -> | ||||||
|             when (item.itemId) { |             when (item.itemId) { | ||||||
|  | @ -721,6 +443,14 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | ||||||
|         } |         } | ||||||
|         APIRepository.dubStatusActive = getApiDubstatusSettings() |         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 |         val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar | ||||||
|  |  | ||||||
|  | @ -2,8 +2,8 @@ package com.lagradost.cloudstream3.animeproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.extractorApis |  | ||||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| import org.jsoup.Jsoup | import org.jsoup.Jsoup | ||||||
| import java.util.* | import java.util.* | ||||||
| 
 | 
 | ||||||
|  | @ -107,8 +107,11 @@ class GogoanimeProvider : MainAPI() { | ||||||
|                 this.name, |                 this.name, | ||||||
|                 TvType.Anime, |                 TvType.Anime, | ||||||
|                 it.selectFirst("img").attr("src"), |                 it.selectFirst("img").attr("src"), | ||||||
|                 it.selectFirst(".released")?.text()?.split(":")?.getOrNull(1)?.trim()?.toIntOrNull(), |                 it.selectFirst(".released")?.text()?.split(":")?.getOrNull(1)?.trim() | ||||||
|                 if (it.selectFirst(".name").text().contains("Dub")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of( |                     ?.toIntOrNull(), | ||||||
|  |                 if (it.selectFirst(".name").text() | ||||||
|  |                         .contains("Dub") | ||||||
|  |                 ) EnumSet.of(DubStatus.Dubbed) else EnumSet.of( | ||||||
|                     DubStatus.Subbed |                     DubStatus.Subbed | ||||||
|                 ), |                 ), | ||||||
|             ) |             ) | ||||||
|  | @ -191,22 +194,20 @@ class GogoanimeProvider : MainAPI() { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun extractVideos(uri: String): List<ExtractorLink> { |     private fun extractVideos(uri: String, callback: (ExtractorLink) -> Unit) { | ||||||
|         val html = app.get(uri).text |         val doc = app.get(uri).document | ||||||
|         val doc = Jsoup.parse(html) | 
 | ||||||
|  |         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 link = iframe.replace("streaming.php", "download") | ||||||
| 
 |  | ||||||
|         val page = app.get(link, headers = mapOf("Referer" to iframe)) |         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")) { |             if (it.hasAttr("download")) { | ||||||
|                 val qual = if (it.text() |                 val qual = if (it.text() | ||||||
|                         .contains("HDP") |                         .contains("HDP") | ||||||
|                 ) "1080" else qualityRegex.find(it.text())?.destructured?.component1().toString() |                 ) "1080" else qualityRegex.find(it.text())?.destructured?.component1().toString() | ||||||
|                 listOf( |                 callback( | ||||||
|                     ExtractorLink( |                     ExtractorLink( | ||||||
|                         "Gogoanime", |                         "Gogoanime", | ||||||
|                         if (qual == "null") "Gogoanime" else "Gogoanime - " + qual + "p", |                         if (qual == "null") "Gogoanime" else "Gogoanime - " + qual + "p", | ||||||
|  | @ -218,16 +219,18 @@ class GogoanimeProvider : MainAPI() { | ||||||
|                 ) |                 ) | ||||||
|             } else { |             } else { | ||||||
|                 val url = it.attr("href") |                 val url = it.attr("href") | ||||||
|                 val extractorLinks = ArrayList<ExtractorLink>() |                 loadExtractor(url, null, callback) | ||||||
|                 for (api in extractorApis) { |             } | ||||||
|                     if (url.startsWith(api.mainUrl)) { |         } | ||||||
|                         extractorLinks.addAll(api.getSafeUrl(url) ?: listOf()) | 
 | ||||||
|                         break |         val streamingResponse = app.get(iframe, headers = mapOf("Referer" to iframe)) | ||||||
|                     } |         streamingResponse.document.select(".list-server-items > .linkserver") | ||||||
|                 } |             ?.forEach { element -> | ||||||
|                 extractorLinks |                 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( |     override fun loadLinks( | ||||||
|  | @ -236,9 +239,7 @@ class GogoanimeProvider : MainAPI() { | ||||||
|         subtitleCallback: (SubtitleFile) -> Unit, |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|         callback: (ExtractorLink) -> Unit |         callback: (ExtractorLink) -> Unit | ||||||
|     ): Boolean { |     ): Boolean { | ||||||
|         for (source in extractVideos(data)) { |         extractVideos(data, callback) | ||||||
|             callback.invoke(source) |  | ||||||
|         } |  | ||||||
|         return true |         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.RemoteMediaClient | ||||||
| import com.google.android.gms.cast.framework.media.uicontroller.UIController | import com.google.android.gms.cast.framework.media.uicontroller.UIController | ||||||
| import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity | 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.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.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.ui.result.ResultEpisode | ||||||
| import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks | import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks | ||||||
| import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo | import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo | ||||||
|  | @ -86,10 +88,11 @@ data class MetadataHolder( | ||||||
|     val currentEpisodeIndex: Int, |     val currentEpisodeIndex: Int, | ||||||
|     val episodes: List<ResultEpisode>, |     val episodes: List<ResultEpisode>, | ||||||
|     val currentLinks: List<ExtractorLink>, |     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()) |     private val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule()) | ||||||
|         .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build() |         .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 } |                         remoteMediaClient?.mediaInfo?.mediaTracks?.filter { it.type == MediaTrack.TYPE_TEXT } | ||||||
|                             ?: ArrayList() |                             ?: 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) |                     bottomSheetDialogBuilder.setView(R.layout.sort_bottom_sheet) | ||||||
|                     val bottomSheetDialog = bottomSheetDialogBuilder.create() |                     val bottomSheetDialog = bottomSheetDialogBuilder.create() | ||||||
|                     bottomSheetDialog.show() |                     bottomSheetDialog.show() | ||||||
|                     //  bottomSheetDialog.setContentView(R.layout.sort_bottom_sheet) |                     //  bottomSheetDialog.setContentView(R.layout.sort_bottom_sheet) | ||||||
|                     val providerList = bottomSheetDialog.findViewById<ListView>(R.id.sort_providers)!! |                     val providerList = | ||||||
|                     val subtitleList = bottomSheetDialog.findViewById<ListView>(R.id.sort_subtitles)!! |                         bottomSheetDialog.findViewById<ListView>(R.id.sort_providers)!! | ||||||
|  |                     val subtitleList = | ||||||
|  |                         bottomSheetDialog.findViewById<ListView>(R.id.sort_subtitles)!! | ||||||
|                     if (subTracks.isEmpty()) { |                     if (subTracks.isEmpty()) { | ||||||
|                         bottomSheetDialog.findViewById<LinearLayout>(R.id.sort_subtitles_holder)?.visibility = GONE |                         bottomSheetDialog.findViewById<LinearLayout>(R.id.sort_subtitles_holder)?.visibility = | ||||||
|  |                             GONE | ||||||
|                     } else { |                     } 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.add(view.context.getString(R.string.no_subtitles)) | ||||||
|                         arrayAdapter.addAll(subTracks.mapNotNull { it.name }) |                         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 sortingMethods = items.map { it.name }.toTypedArray() | ||||||
|                     val sotringIndex = items.indexOfFirst { it.url == contentUrl } |                     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()) |                     arrayAdapter.addAll(sortingMethods.toMutableList()) | ||||||
| 
 | 
 | ||||||
|                     providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE |                     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 |                             try { // THIS IS VERY IMPORTANT BECAUSE WE NEVER WANT TO AUTOLOAD THE NEXT EPISODE | ||||||
|                                 val currentIdIndex = remoteMediaClient?.getItemIndex() |                                 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) { |                                 if (currentIdIndex == null && nextId != null) { | ||||||
|                                     awaitLinks( |                                     awaitLinks( | ||||||
|                                         remoteMediaClient?.queueInsertAndPlayItem( |                                         remoteMediaClient?.queueInsertAndPlayItem( | ||||||
|  | @ -256,26 +267,29 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | ||||||
|                     thread { |                     thread { | ||||||
|                         val index = meta.currentEpisodeIndex + 1 |                         val index = meta.currentEpisodeIndex + 1 | ||||||
|                         val epData = meta.episodes[index] |                         val epData = meta.episodes[index] | ||||||
|                         val links = ArrayList<ExtractorLink>() |                         val currentLinks = mutableSetOf<ExtractorLink>() | ||||||
|                         val subs = ArrayList<SubtitleFile>() |                         val currentSubs = mutableSetOf<SubtitleData>() | ||||||
| 
 | 
 | ||||||
|                         val isSuccessful = |                         val generator = RepoLinkGenerator(listOf(epData)) | ||||||
|                             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) |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
| 
 | 
 | ||||||
|                         if (isSuccessful) { |                         val isSuccessful = normalSafeApiCall { | ||||||
|                             val sorted = sortUrls(links) |                             generator.generateLinks(false, true, | ||||||
|                             if (sorted.isNotEmpty()) { |                                 { | ||||||
|  |                                     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( |                                 val jsonCopy = meta.copy( | ||||||
|                                     currentLinks = sorted, |                                     currentLinks =  sortedLinks, | ||||||
|                                     currentSubtitles = subs, |                                     currentSubtitles = sortedSubs, | ||||||
|                                     currentEpisodeIndex = index |                                     currentEpisodeIndex = index | ||||||
|                                 ) |                                 ) | ||||||
| 
 | 
 | ||||||
|  | @ -287,7 +301,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | ||||||
|                                     jsonCopy, |                                     jsonCopy, | ||||||
|                                     0, |                                     0, | ||||||
|                                     done, |                                     done, | ||||||
|                                     subs |                                     sortedSubs | ||||||
|                                 ) |                                 ) | ||||||
| 
 | 
 | ||||||
|                                 /*fun loadIndex(index: Int) { |                                 /*fun loadIndex(index: Int) { | ||||||
|  | @ -367,9 +381,21 @@ class ControllerActivity : ExpandedControllerActivity() { | ||||||
|         val skipBackButton: ImageView = getButtonImageViewAt(1) |         val skipBackButton: ImageView = getButtonImageViewAt(1) | ||||||
|         val skipForwardButton: ImageView = getButtonImageViewAt(2) |         val skipForwardButton: ImageView = getButtonImageViewAt(2) | ||||||
|         val skipOpButton: ImageView = getButtonImageViewAt(3) |         val skipOpButton: ImageView = getButtonImageViewAt(3) | ||||||
|         uiMediaController.bindViewToUIController(sourcesButton, SelectSourceController(sourcesButton, this)) |         uiMediaController.bindViewToUIController( | ||||||
|         uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false)) |             sourcesButton, | ||||||
|         uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true)) |             SelectSourceController(sourcesButton, this) | ||||||
|         uiMediaController.bindViewToUIController(skipOpButton, SkipNextEpisodeController(skipOpButton)) |         ) | ||||||
|  |         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.content.DialogInterface | ||||||
| import android.widget.Toast | import android.widget.Toast | ||||||
| import androidx.appcompat.app.AlertDialog | 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.R | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.ui.player.PlayerFragment | import com.lagradost.cloudstream3.ui.player.DownloadFileGenerator | ||||||
| import com.lagradost.cloudstream3.ui.player.UriData | import com.lagradost.cloudstream3.ui.player.GeneratorPlayer | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.getNameFull | import com.lagradost.cloudstream3.utils.AppUtils.getNameFull | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos | import com.lagradost.cloudstream3.utils.ExtractorUri | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.navigate | import com.lagradost.cloudstream3.utils.UIHelper.navigate | ||||||
| import com.lagradost.cloudstream3.utils.VideoDownloadHelper | import com.lagradost.cloudstream3.utils.VideoDownloadHelper | ||||||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager | import com.lagradost.cloudstream3.utils.VideoDownloadManager | ||||||
|  | @ -49,7 +50,7 @@ object DownloadButtonSetup { | ||||||
|                             .setPositiveButton(R.string.delete, dialogClickListener) |                             .setPositiveButton(R.string.delete, dialogClickListener) | ||||||
|                             .setNegativeButton(R.string.cancel, dialogClickListener) |                             .setNegativeButton(R.string.cancel, dialogClickListener) | ||||||
|                             .show() |                             .show() | ||||||
|                     } catch (e : Exception) { |                     } catch (e: Exception) { | ||||||
|                         logError(e) |                         logError(e) | ||||||
|                         // ye you somehow fucked up formatting did you? |                         // ye you somehow fucked up formatting did you? | ||||||
|                     } |                     } | ||||||
|  | @ -81,40 +82,71 @@ object DownloadButtonSetup { | ||||||
|             DOWNLOAD_ACTION_LONG_CLICK -> { |             DOWNLOAD_ACTION_LONG_CLICK -> { | ||||||
|                 activity?.let { act -> |                 activity?.let { act -> | ||||||
|                     val length = |                     val length = | ||||||
|                         VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(act, click.data.id)?.fileLength |                         VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( | ||||||
|  |                             act, | ||||||
|  |                             click.data.id | ||||||
|  |                         )?.fileLength | ||||||
|                             ?: 0 |                             ?: 0 | ||||||
|                     if (length > 0) { |                     if (length > 0) { | ||||||
|                         MainActivity.showToast(act, R.string.delete, Toast.LENGTH_LONG) |                         showToast(act, R.string.delete, Toast.LENGTH_LONG) | ||||||
|                     } else { |                     } else { | ||||||
|                         MainActivity.showToast(act, R.string.download, Toast.LENGTH_LONG) |                         showToast(act, R.string.download, Toast.LENGTH_LONG) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             DOWNLOAD_ACTION_PLAY_FILE -> { |             DOWNLOAD_ACTION_PLAY_FILE -> { | ||||||
|                 activity?.let { act -> |                 activity?.let { act -> | ||||||
|                     val info = |                     val info = | ||||||
|                         VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(act, click.data.id) |                         VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( | ||||||
|                             ?: return |                             act, | ||||||
|                     val keyInfo = act.getKey<VideoDownloadManager.DownloadedFileInfo>( |                             click.data.id | ||||||
|  |                         ) ?: return | ||||||
|  |                     val keyInfo = getKey<VideoDownloadManager.DownloadedFileInfo>( | ||||||
|                         VideoDownloadManager.KEY_DOWNLOAD_INFO, |                         VideoDownloadManager.KEY_DOWNLOAD_INFO, | ||||||
|                         click.data.id.toString() |                         click.data.id.toString() | ||||||
|                     ) ?: return |                     ) ?: return | ||||||
|  |                     val parent = getKey<VideoDownloadHelper.DownloadHeaderCached>( | ||||||
|  |                         DOWNLOAD_HEADER_CACHE, | ||||||
|  |                         click.data.parentId.toString() | ||||||
|  |                     ) ?: return | ||||||
| 
 | 
 | ||||||
|                     act.navigate( |                     act.navigate( | ||||||
|                         R.id.global_to_navigation_player, PlayerFragment.newInstance( |                         R.id.global_to_navigation_player, GeneratorPlayer.newInstance( | ||||||
|                             UriData( |                             DownloadFileGenerator( | ||||||
|                                 info.path.toString(), |                                 listOf( | ||||||
|                                 keyInfo.basePath, |                                     ExtractorUri( | ||||||
|                                 keyInfo.relativePath, |                                         uri = info.path, | ||||||
|                                 keyInfo.displayName, | 
 | ||||||
|                                 click.data.parentId, |                                         id = click.data.id, | ||||||
|                                 click.data.id, |                                         parentId = click.data.parentId, | ||||||
|                                 headerName ?: "null", |                                         name = act.getString(R.string.downloaded_file), //click.data.name ?: keyInfo.displayName | ||||||
|                                 if (click.data.episode <= 0) null else click.data.episode, |                                         season = click.data.season, | ||||||
|                                 click.data.season |                                         episode = click.data.episode, | ||||||
|                             ), |                                         headerName = parent.name, | ||||||
|                             getViewPos(click.data.id)?.position ?: 0 |                                         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) |                         logError(e) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 else -> { |                 else -> Unit | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             _page.postValue(data) |             _page.postValue(data) | ||||||
|         } else { |         } 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) { |             when (callback.action) { | ||||||
|                 SEARCH_ACTION_LOAD -> { |                 SEARCH_ACTION_LOAD -> { | ||||||
|                     if (isMainApis) { |                     if (isMainApis) { | ||||||
|                         // this is due to result page only holding 1 thing |  | ||||||
|                         activity?.popCurrentPage() |  | ||||||
|                         activity?.popCurrentPage() |                         activity?.popCurrentPage() | ||||||
| 
 | 
 | ||||||
|                         SearchHelper.handleSearchClickCallback(activity, callback) |                         SearchHelper.handleSearchClickCallback(activity, callback) | ||||||
|  |  | ||||||
|  | @ -7,8 +7,10 @@ import android.view.ViewGroup | ||||||
| import android.widget.ImageView | import android.widget.ImageView | ||||||
| import android.widget.TextView | import android.widget.TextView | ||||||
| import androidx.annotation.LayoutRes | import androidx.annotation.LayoutRes | ||||||
|  | import androidx.core.view.isVisible | ||||||
| import androidx.core.widget.ContentLoadingProgressBar | import androidx.core.widget.ContentLoadingProgressBar | ||||||
| import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | import com.google.android.material.button.MaterialButton | ||||||
| import com.lagradost.cloudstream3.R | import com.lagradost.cloudstream3.R | ||||||
| import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD | import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD | ||||||
| import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder | 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.UIHelper.setImage | ||||||
| import com.lagradost.cloudstream3.utils.VideoDownloadHelper | import com.lagradost.cloudstream3.utils.VideoDownloadHelper | ||||||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager | 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_holder | ||||||
| import kotlinx.android.synthetic.main.result_episode.view.episode_text | 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.* | ||||||
|  | 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.* | import java.util.* | ||||||
| 
 | 
 | ||||||
| const val ACTION_PLAY_EPISODE_IN_PLAYER = 1 | const val ACTION_PLAY_EPISODE_IN_PLAYER = 1 | ||||||
|  | @ -125,6 +132,7 @@ class EpisodeAdapter( | ||||||
|         override var downloadButton = EasyDownloadButton() |         override var downloadButton = EasyDownloadButton() | ||||||
| 
 | 
 | ||||||
|         private val episodeText: TextView = itemView.episode_text |         private val episodeText: TextView = itemView.episode_text | ||||||
|  |         private val episodeFiller: MaterialButton? = itemView.episode_filler | ||||||
|         private val episodeRating: TextView? = itemView.episode_rating |         private val episodeRating: TextView? = itemView.episode_rating | ||||||
|         private val episodeDescript: TextView? = itemView.episode_descript |         private val episodeDescript: TextView? = itemView.episode_descript | ||||||
|         private val episodeProgress: ContentLoadingProgressBar? = itemView.episode_progress |         private val episodeProgress: ContentLoadingProgressBar? = itemView.episode_progress | ||||||
|  | @ -142,7 +150,8 @@ class EpisodeAdapter( | ||||||
|             localCard = card |             localCard = card | ||||||
| 
 | 
 | ||||||
|             val name = if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}" |             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 |             episodeText.isSelected = true // is needed for text repeating | ||||||
| 
 | 
 | ||||||
|             val displayPos = card.getDisplayPosition() |             val displayPos = card.getDisplayPosition() | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ import androidx.core.view.isGone | ||||||
| import androidx.core.view.isVisible | import androidx.core.view.isVisible | ||||||
| import androidx.core.widget.NestedScrollView | import androidx.core.widget.NestedScrollView | ||||||
| import androidx.fragment.app.Fragment | import androidx.fragment.app.Fragment | ||||||
| import androidx.fragment.app.activityViewModels | import androidx.lifecycle.ViewModelProvider | ||||||
| import androidx.preference.PreferenceManager | import androidx.preference.PreferenceManager | ||||||
| import androidx.recyclerview.widget.GridLayoutManager | import androidx.recyclerview.widget.GridLayoutManager | ||||||
| import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | @ -35,12 +35,9 @@ import com.google.android.material.button.MaterialButton | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.APIHolder.getApiFromName | import com.lagradost.cloudstream3.APIHolder.getApiFromName | ||||||
| import com.lagradost.cloudstream3.APIHolder.getId | import com.lagradost.cloudstream3.APIHolder.getId | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.getCastSession | import com.lagradost.cloudstream3.CommonActivity.getCastSession | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.showToast | import com.lagradost.cloudstream3.CommonActivity.showToast | ||||||
| import com.lagradost.cloudstream3.mvvm.Resource | import com.lagradost.cloudstream3.mvvm.* | ||||||
| import com.lagradost.cloudstream3.mvvm.logError |  | ||||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall |  | ||||||
| import com.lagradost.cloudstream3.mvvm.observe |  | ||||||
| import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis | import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis | ||||||
| import com.lagradost.cloudstream3.syncproviders.SyncAPI | import com.lagradost.cloudstream3.syncproviders.SyncAPI | ||||||
| import com.lagradost.cloudstream3.ui.WatchType | 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.DOWNLOAD_NAVIGATE_TO | ||||||
| import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick | import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick | ||||||
| import com.lagradost.cloudstream3.ui.download.EasyDownloadButton | import com.lagradost.cloudstream3.ui.download.EasyDownloadButton | ||||||
| import com.lagradost.cloudstream3.ui.player.PlayerData | import com.lagradost.cloudstream3.ui.player.GeneratorPlayer | ||||||
| import com.lagradost.cloudstream3.ui.player.PlayerFragment | import com.lagradost.cloudstream3.ui.player.SubtitleData | ||||||
| import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment | import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment | ||||||
| import com.lagradost.cloudstream3.ui.search.SearchAdapter | import com.lagradost.cloudstream3.ui.search.SearchAdapter | ||||||
| import com.lagradost.cloudstream3.ui.search.SearchHelper | 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.isAppInstalled | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable | import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast | 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.AppUtils.openBrowser | ||||||
| import com.lagradost.cloudstream3.utils.CastHelper.startCast | import com.lagradost.cloudstream3.utils.CastHelper.startCast | ||||||
| import com.lagradost.cloudstream3.utils.Coroutines.main | import com.lagradost.cloudstream3.utils.Coroutines.main | ||||||
|  | @ -97,6 +95,7 @@ const val START_ACTION_LOAD_EP = 2 | ||||||
| const val START_VALUE_NORMAL = 0 | const val START_VALUE_NORMAL = 0 | ||||||
| 
 | 
 | ||||||
| data class ResultEpisode( | data class ResultEpisode( | ||||||
|  |     val headerName: String, | ||||||
|     val name: String?, |     val name: String?, | ||||||
|     val poster: String?, |     val poster: String?, | ||||||
|     val episode: Int, |     val episode: Int, | ||||||
|  | @ -110,6 +109,8 @@ data class ResultEpisode( | ||||||
|     val rating: Int?, |     val rating: Int?, | ||||||
|     val description: String?, |     val description: String?, | ||||||
|     val isFiller: Boolean?, |     val isFiller: Boolean?, | ||||||
|  |     val tvType: TvType, | ||||||
|  |     val parentId: Int?, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| fun ResultEpisode.getRealPosition(): Long { | fun ResultEpisode.getRealPosition(): Long { | ||||||
|  | @ -129,6 +130,7 @@ fun ResultEpisode.getDisplayPosition(): Long { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun buildResultEpisode( | fun buildResultEpisode( | ||||||
|  |     headerName: String, | ||||||
|     name: String?, |     name: String?, | ||||||
|     poster: String?, |     poster: String?, | ||||||
|     episode: Int, |     episode: Int, | ||||||
|  | @ -140,9 +142,12 @@ fun buildResultEpisode( | ||||||
|     rating: Int?, |     rating: Int?, | ||||||
|     description: String?, |     description: String?, | ||||||
|     isFiller: Boolean?, |     isFiller: Boolean?, | ||||||
|  |     tvType: TvType, | ||||||
|  |     parentId: Int?, | ||||||
| ): ResultEpisode { | ): ResultEpisode { | ||||||
|     val posDur = getViewPos(id) |     val posDur = getViewPos(id) | ||||||
|     return ResultEpisode( |     return ResultEpisode( | ||||||
|  |         headerName, | ||||||
|         name, |         name, | ||||||
|         poster, |         poster, | ||||||
|         episode, |         episode, | ||||||
|  | @ -155,7 +160,9 @@ fun buildResultEpisode( | ||||||
|         posDur?.duration ?: 0, |         posDur?.duration ?: 0, | ||||||
|         rating, |         rating, | ||||||
|         description, |         description, | ||||||
|         isFiller |         isFiller, | ||||||
|  |         tvType, | ||||||
|  |         parentId, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -184,9 +191,7 @@ class ResultFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|     private var currentLoadingCount = |     private var currentLoadingCount = | ||||||
|         0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED |         0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED | ||||||
|     private val viewModel: ResultViewModel by activityViewModels() |     private lateinit var viewModel: ResultViewModel //by activityViewModels() | ||||||
|     private var allEpisodes: HashMap<Int, List<ExtractorLink>> = HashMap() |  | ||||||
|     private var allEpisodesSubs: HashMap<Int, HashMap<String, SubtitleFile>> = HashMap() |  | ||||||
|     private var currentHeaderName: String? = null |     private var currentHeaderName: String? = null | ||||||
|     private var currentType: TvType? = null |     private var currentType: TvType? = null | ||||||
|     private var currentEpisodes: List<ResultEpisode>? = null |     private var currentEpisodes: List<ResultEpisode>? = null | ||||||
|  | @ -197,8 +202,8 @@ class ResultFragment : Fragment() { | ||||||
|         container: ViewGroup?, |         container: ViewGroup?, | ||||||
|         savedInstanceState: Bundle?, |         savedInstanceState: Bundle?, | ||||||
|     ): View? { |     ): View? { | ||||||
|         // viewModel = |         viewModel = | ||||||
|         //     ViewModelProvider(activity ?: this).get(ResultViewModel::class.java) |             ViewModelProvider(this)[ResultViewModel::class.java] | ||||||
|         return inflater.inflate(R.layout.fragment_result, container, false) |         return inflater.inflate(R.layout.fragment_result, container, false) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -360,6 +365,7 @@ class ResultFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|         activity?.window?.decorView?.clearFocus() |         activity?.window?.decorView?.clearFocus() | ||||||
|         hideKeyboard() |         hideKeyboard() | ||||||
|  |         activity?.loadCache() | ||||||
| 
 | 
 | ||||||
|         activity?.fixPaddingStatusbar(result_scroll) |         activity?.fixPaddingStatusbar(result_scroll) | ||||||
|         //activity?.fixPaddingStatusbar(result_barstatus) |         //activity?.fixPaddingStatusbar(result_barstatus) | ||||||
|  | @ -431,74 +437,21 @@ class ResultFragment : Fragment() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         fun handleAction(episodeClick: EpisodeClickEvent): Job = main { |         fun handleAction(episodeClick: EpisodeClickEvent): Job = main { | ||||||
|  |             var currentLinks: Set<ExtractorLink>? = null | ||||||
|  |             var currentSubs: Set<SubtitleData>? = null | ||||||
|  | 
 | ||||||
|             //val id = episodeClick.data.id |             //val id = episodeClick.data.id | ||||||
|             val index = episodeClick.data.index |  | ||||||
|             val buildInPlayer = true |  | ||||||
|             currentLoadingCount++ |             currentLoadingCount++ | ||||||
|             var currentLinks: List<ExtractorLink>? = null |  | ||||||
|             var currentSubs: HashMap<String, SubtitleFile>? = null |  | ||||||
| 
 | 
 | ||||||
|             val showTitle = |             val showTitle = | ||||||
|                 episodeClick.data.name ?: context?.getString(R.string.episode_name_format)?.format( |                 episodeClick.data.name ?: context?.getString(R.string.episode_name_format) | ||||||
|                     getString(R.string.episode), |                     ?.format( | ||||||
|                     episodeClick.data.episode |                         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 |             fun acquireSingleExtractorLink( | ||||||
| 
 |  | ||||||
|                 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( |  | ||||||
|                 links: List<ExtractorLink>, |                 links: List<ExtractorLink>, | ||||||
|                 title: String, |                 title: String, | ||||||
|                 callback: (ExtractorLink) -> Unit |                 callback: (ExtractorLink) -> Unit | ||||||
|  | @ -514,7 +467,7 @@ class ResultFragment : Fragment() { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fun acquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) { |             fun acquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) { | ||||||
|                 acquireSingeExtractorLink(currentLinks ?: return, title, callback) |                 acquireSingleExtractorLink(sortUrls(currentLinks ?: return), title, callback) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fun startChromecast(startIndex: Int) { |             fun startChromecast(startIndex: Int) { | ||||||
|  | @ -527,13 +480,13 @@ class ResultFragment : Fragment() { | ||||||
|                     episodeClick.data.index, |                     episodeClick.data.index, | ||||||
|                     eps, |                     eps, | ||||||
|                     sortUrls(currentLinks ?: return), |                     sortUrls(currentLinks ?: return), | ||||||
|                     currentSubs?.values?.toList() ?: emptyList(), |                     sortSubs(currentSubs ?: return), | ||||||
|                     startTime = episodeClick.data.getRealPosition(), |                     startTime = episodeClick.data.getRealPosition(), | ||||||
|                     startIndex = startIndex |                     startIndex = startIndex | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleFile>?) { |             fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleData>?) { | ||||||
|                 val isMovie = currentIsMovie ?: return |                 val isMovie = currentIsMovie ?: return | ||||||
|                 val titleName = sanitizeFilename(currentHeaderName ?: return) |                 val titleName = sanitizeFilename(currentHeaderName ?: return) | ||||||
| 
 | 
 | ||||||
|  | @ -615,12 +568,12 @@ class ResultFragment : Fragment() { | ||||||
|                             subsList.filter { |                             subsList.filter { | ||||||
|                                 downloadList.contains( |                                 downloadList.contains( | ||||||
|                                     SubtitleHelper.fromLanguageToTwoLetters( |                                     SubtitleHelper.fromLanguageToTwoLetters( | ||||||
|                                         it.lang, |                                         it.name, | ||||||
|                                         true |                                         true | ||||||
|                                     ) |                                     ) | ||||||
|                                 ) |                                 ) | ||||||
|                             } |                             } | ||||||
|                                 .map { ExtractorSubtitleLink(it.lang, it.url, "") } |                                 .map { ExtractorSubtitleLink(it.name, it.url, "") } | ||||||
|                                 .forEach { link -> |                                 .forEach { link -> | ||||||
|                                     val epName = meta.name |                                     val epName = meta.name | ||||||
|                                         ?: "${context?.getString(R.string.episode)} ${meta.episode}" |                                         ?: "${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) { |             val isLoaded = when (episodeClick.action) { | ||||||
|                 ACTION_PLAY_EPISODE_IN_PLAYER -> true |                 ACTION_PLAY_EPISODE_IN_PLAYER -> true | ||||||
|                 ACTION_CLICK_DEFAULT -> true |                 ACTION_CLICK_DEFAULT -> true | ||||||
|                 ACTION_SHOW_TOAST -> 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_EPISODE -> requireLinks(true) | ||||||
|                 ACTION_CHROME_CAST_MIRROR -> requireLinks(true) |                 ACTION_CHROME_CAST_MIRROR -> requireLinks(true) | ||||||
|                 else -> requireLinks(false) |                 else -> requireLinks(false) | ||||||
|  | @ -781,17 +780,15 @@ class ResultFragment : Fragment() { | ||||||
|                                 if (act.checkWrite()) return@main |                                 if (act.checkWrite()) return@main | ||||||
|                             } |                             } | ||||||
|                             val data = currentLinks ?: return@main |                             val data = currentLinks ?: return@main | ||||||
|                             val subs = currentSubs |                             val subs = currentSubs ?: return@main | ||||||
| 
 | 
 | ||||||
|                             val outputDir = act.cacheDir |                             val outputDir = act.cacheDir | ||||||
|                             val outputFile = withContext(Dispatchers.IO) { |                             val outputFile = withContext(Dispatchers.IO) { | ||||||
|                                 File.createTempFile("mirrorlist", ".m3u8", outputDir) |                                 File.createTempFile("mirrorlist", ".m3u8", outputDir) | ||||||
|                             } |                             } | ||||||
|                             var text = "#EXTM3U" |                             var text = "#EXTM3U" | ||||||
|                             if (subs != null) { |                             for (sub in sortSubs(subs)) { | ||||||
|                                 for (sub in subs.values) { |                                 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}\"" | ||||||
|                                     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 (link in data.sortedBy { -it.quality }) { |                             for (link in data.sortedBy { -it.quality }) { | ||||||
|                                 text += "\n#EXTINF:, ${link.name}\n${link.url}" |                                 text += "\n#EXTINF:, ${link.name}\n${link.url}" | ||||||
|  | @ -836,13 +833,16 @@ class ResultFragment : Fragment() { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ACTION_PLAY_EPISODE_IN_PLAYER -> { |                 ACTION_PLAY_EPISODE_IN_PLAYER -> { | ||||||
|                     if (buildInPlayer) { |                     currentEpisodes?.let { episodes -> | ||||||
|                         activity.navigate( |                         viewModel.getGenerator(episodes.indexOf(episodeClick.data)) | ||||||
|                             R.id.global_to_navigation_player, PlayerFragment.newInstance( |                             ?.let { generator -> | ||||||
|                                 PlayerData(index, null, 0), |                                 activity?.navigate( | ||||||
|                                 episodeClick.data.getRealPosition() |                                     R.id.global_to_navigation_player, | ||||||
|                             ) |                                     GeneratorPlayer.newInstance( | ||||||
|                         ) |                                         generator | ||||||
|  |                                     ) | ||||||
|  |                                 ) | ||||||
|  |                             } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | @ -852,27 +852,29 @@ class ResultFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|                 ACTION_DOWNLOAD_EPISODE -> { |                 ACTION_DOWNLOAD_EPISODE -> { | ||||||
|                     startDownload( |                     startDownload( | ||||||
|                         currentLinks ?: return@main, |                         sortUrls(currentLinks ?: return@main), | ||||||
|                         currentSubs?.values?.toList() ?: emptyList() |                         sortSubs(currentSubs ?: return@main) | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ACTION_DOWNLOAD_MIRROR -> { |                 ACTION_DOWNLOAD_MIRROR -> { | ||||||
|                     currentLinks?.let { links -> |                     acquireSingleExtractorLink( | ||||||
|                         acquireSingeExtractorLink( |                         sortUrls( | ||||||
|                             links,//(currentLinks ?: return@main).filter { !it.isM3u8 }, |                             currentLinks ?: return@main | ||||||
|                             getString(R.string.episode_action_download_mirror) |                         ),//(currentLinks ?: return@main).filter { !it.isM3u8 }, | ||||||
|                         ) { link -> |                         getString(R.string.episode_action_download_mirror) | ||||||
|                             startDownload( |                     ) { link -> | ||||||
|                                 listOf(link), |                         showToast(activity, R.string.download_started, Toast.LENGTH_SHORT) | ||||||
|                                 currentSubs?.values?.toList() ?: emptyList() |                         startDownload( | ||||||
|                             ) |                             listOf(link), | ||||||
|                         } |                             sortSubs(currentSubs ?: return@acquireSingleExtractorLink) | ||||||
|  |                         ) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = |         val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = | ||||||
|             EpisodeAdapter( |             EpisodeAdapter( | ||||||
|                 ArrayList(), |                 ArrayList(), | ||||||
|  | @ -947,8 +949,7 @@ class ResultFragment : Fragment() { | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 else -> { |                 else -> Unit | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             arguments?.remove("startValue") |             arguments?.remove("startValue") | ||||||
|             arguments?.remove("startAction") |             arguments?.remove("startAction") | ||||||
|  | @ -956,19 +957,13 @@ class ResultFragment : Fragment() { | ||||||
|             startValue = null |             startValue = null | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         observe(viewModel.allEpisodes) { |         observe(viewModel.selectedSeason) | ||||||
|             allEpisodes = it |         { season -> | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         observe(viewModel.allEpisodesSubs) { |  | ||||||
|             allEpisodesSubs = it |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         observe(viewModel.selectedSeason) { season -> |  | ||||||
|             result_season_button?.text = fromIndexToSeasonText(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?.visibility = if (seasonList.size <= 1) GONE else VISIBLE | ||||||
|             result_season_button?.setOnClickListener { |             result_season_button?.setOnClickListener { | ||||||
|                 result_season_button?.popupMenuNoIconsAndNoStringRes( |                 result_season_button?.popupMenuNoIconsAndNoStringRes( | ||||||
|  | @ -982,7 +977,8 @@ class ResultFragment : Fragment() { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         observe(viewModel.publicEpisodes) { episodes -> |         observe(viewModel.publicEpisodes) | ||||||
|  |         { episodes -> | ||||||
|             when (episodes) { |             when (episodes) { | ||||||
|                 is Resource.Failure -> { |                 is Resource.Failure -> { | ||||||
|                     result_episode_loading?.isVisible = false |                     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() |             result_dub_select?.text = status.toString() | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         observe(viewModel.dubSubSelections) { range -> |         observe(viewModel.dubSubSelections) | ||||||
|  |         { range -> | ||||||
|             dubRange = range |             dubRange = range | ||||||
|             result_dub_select?.visibility = if (range.size <= 1) GONE else VISIBLE |             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 |             result_episode_select?.text = range | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -1069,8 +1068,7 @@ class ResultFragment : Fragment() { | ||||||
|                         setDuration(d.duration) |                         setDuration(d.duration) | ||||||
|                         setRating(d.publicScore) |                         setRating(d.publicScore) | ||||||
|                     } |                     } | ||||||
|                     else -> { |                     else -> Unit | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -1277,6 +1275,7 @@ class ResultFragment : Fragment() { | ||||||
|                                                 EpisodeClickEvent( |                                                 EpisodeClickEvent( | ||||||
|                                                     ACTION_DOWNLOAD_EPISODE, |                                                     ACTION_DOWNLOAD_EPISODE, | ||||||
|                                                     ResultEpisode( |                                                     ResultEpisode( | ||||||
|  |                                                         d.name, | ||||||
|                                                         d.name, |                                                         d.name, | ||||||
|                                                         null, |                                                         null, | ||||||
|                                                         0, |                                                         0, | ||||||
|  | @ -1290,6 +1289,8 @@ class ResultFragment : Fragment() { | ||||||
|                                                         null, |                                                         null, | ||||||
|                                                         null, |                                                         null, | ||||||
|                                                         null, |                                                         null, | ||||||
|  |                                                         d.type, | ||||||
|  |                                                         localId, | ||||||
|                                                     ) |                                                     ) | ||||||
|                                                 ) |                                                 ) | ||||||
|                                             ) |                                             ) | ||||||
|  | @ -1371,7 +1372,7 @@ class ResultFragment : Fragment() { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (restart || viewModel.resultResponse.value == null) { |                 if (restart || viewModel.resultResponse.value == null) { | ||||||
|                     viewModel.clear() |                     //viewModel.clear() | ||||||
|                     viewModel.load(tempUrl, apiName, showFillers) |                     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.APIHolder.getId | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | ||||||
| import com.lagradost.cloudstream3.mvvm.Resource | import com.lagradost.cloudstream3.mvvm.Resource | ||||||
|  | import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||||
| import com.lagradost.cloudstream3.mvvm.safeApiCall | import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||||
| import com.lagradost.cloudstream3.syncproviders.SyncAPI | import com.lagradost.cloudstream3.syncproviders.SyncAPI | ||||||
| import com.lagradost.cloudstream3.ui.APIRepository | import com.lagradost.cloudstream3.ui.APIRepository | ||||||
| import com.lagradost.cloudstream3.ui.WatchType | 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.* | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData | import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub | import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub | ||||||
|  | @ -37,24 +41,9 @@ const val EPISODE_RANGE_SIZE = 50 | ||||||
| const val EPISODE_RANGE_OVERLOAD = 60 | const val EPISODE_RANGE_OVERLOAD = 60 | ||||||
| 
 | 
 | ||||||
| class ResultViewModel : ViewModel() { | 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 repo: APIRepository? = null | ||||||
|  |     private var generator: IGenerator? = null | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData() |     private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData() | ||||||
|     private val _episodes: MutableLiveData<List<ResultEpisode>> = 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 { |     fun updateSync(context: Context?, sync: List<Pair<SyncAPI, String>>) = viewModelScope.launch { | ||||||
|         if (context == null) return@launch |         if (context == null) return@launch | ||||||
| 
 | 
 | ||||||
|  | @ -225,6 +243,8 @@ class ResultViewModel : ViewModel() { | ||||||
| 
 | 
 | ||||||
|     private fun updateEpisodes(localId: Int?, list: List<ResultEpisode>, selection: Int?) { |     private fun updateEpisodes(localId: Int?, list: List<ResultEpisode>, selection: Int?) { | ||||||
|         _episodes.postValue(list) |         _episodes.postValue(list) | ||||||
|  |         generator = RepoLinkGenerator(list) | ||||||
|  | 
 | ||||||
|         val set = HashMap<Int, Int>() |         val set = HashMap<Int, Int>() | ||||||
| 
 | 
 | ||||||
|         list.withIndex().forEach { set[it.value.id] = it.index } |         list.withIndex().forEach { set[it.value.id] = it.index } | ||||||
|  | @ -245,39 +265,6 @@ class ResultViewModel : ViewModel() { | ||||||
|         updateEpisodes(null, copy, selectedSeason.value) |         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? { |     private fun filterName(name: String?): String? { | ||||||
|         if (name == null) return null |         if (name == null) return null | ||||||
|         Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let { |         Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let { | ||||||
|  | @ -306,7 +293,7 @@ class ResultViewModel : ViewModel() { | ||||||
|         } |         } | ||||||
|         repo = APIRepository(api) |         repo = APIRepository(api) | ||||||
| 
 | 
 | ||||||
|         val data = repo?.load(url) |         val data = repo?.load(url) ?: return@launch | ||||||
| 
 | 
 | ||||||
|         _resultResponse.postValue(data) |         _resultResponse.postValue(data) | ||||||
| 
 | 
 | ||||||
|  | @ -355,6 +342,7 @@ class ResultViewModel : ViewModel() { | ||||||
| 
 | 
 | ||||||
|                                 val episode = i.episode ?: (index + 1) |                                 val episode = i.episode ?: (index + 1) | ||||||
|                                 episodes.add(buildResultEpisode( |                                 episodes.add(buildResultEpisode( | ||||||
|  |                                     d.name, | ||||||
|                                     filterName(i.name), |                                     filterName(i.name), | ||||||
|                                     i.posterUrl, |                                     i.posterUrl, | ||||||
|                                     episode, |                                     episode, | ||||||
|  | @ -368,6 +356,8 @@ class ResultViewModel : ViewModel() { | ||||||
|                                     if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let { |                                     if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let { | ||||||
|                                         it.contains(episode) && it[episode] == true |                                         it.contains(episode) && it[episode] == true | ||||||
|                                     } ?: false else false, |                                     } ?: false else false, | ||||||
|  |                                     d.type, | ||||||
|  |                                     mainId | ||||||
|                                 )) |                                 )) | ||||||
|                             } |                             } | ||||||
|                             idIndex++ |                             idIndex++ | ||||||
|  | @ -386,6 +376,7 @@ class ResultViewModel : ViewModel() { | ||||||
|                         for ((index, i) in d.episodes.withIndex()) { |                         for ((index, i) in d.episodes.withIndex()) { | ||||||
|                             episodes.add( |                             episodes.add( | ||||||
|                                 buildResultEpisode( |                                 buildResultEpisode( | ||||||
|  |                                     d.name, | ||||||
|                                     filterName(i.name), |                                     filterName(i.name), | ||||||
|                                     i.posterUrl, |                                     i.posterUrl, | ||||||
|                                     i.episode ?: (index + 1), |                                     i.episode ?: (index + 1), | ||||||
|  | @ -397,6 +388,8 @@ class ResultViewModel : ViewModel() { | ||||||
|                                     i.rating, |                                     i.rating, | ||||||
|                                     i.description, |                                     i.description, | ||||||
|                                     null, |                                     null, | ||||||
|  |                                     d.type, | ||||||
|  |                                     mainId | ||||||
|                                 ) |                                 ) | ||||||
|                             ) |                             ) | ||||||
| 
 | 
 | ||||||
|  | @ -405,6 +398,7 @@ class ResultViewModel : ViewModel() { | ||||||
|                     } |                     } | ||||||
|                     is MovieLoadResponse -> { |                     is MovieLoadResponse -> { | ||||||
|                         buildResultEpisode( |                         buildResultEpisode( | ||||||
|  |                             d.name, | ||||||
|                             d.name, |                             d.name, | ||||||
|                             null, |                             null, | ||||||
|                             0, |                             0, | ||||||
|  | @ -416,6 +410,8 @@ class ResultViewModel : ViewModel() { | ||||||
|                             null, |                             null, | ||||||
|                             null, |                             null, | ||||||
|                             null, |                             null, | ||||||
|  |                             d.type, | ||||||
|  |                             mainId | ||||||
|                         ).let { |                         ).let { | ||||||
|                             updateEpisodes(mainId, listOf(it), -1) |                             updateEpisodes(mainId, listOf(it), -1) | ||||||
|                         } |                         } | ||||||
|  | @ -424,6 +420,7 @@ class ResultViewModel : ViewModel() { | ||||||
|                         updateEpisodes( |                         updateEpisodes( | ||||||
|                             mainId, listOf( |                             mainId, listOf( | ||||||
|                                 buildResultEpisode( |                                 buildResultEpisode( | ||||||
|  |                                     d.name, | ||||||
|                                     d.name, |                                     d.name, | ||||||
|                                     null, |                                     null, | ||||||
|                                     0, |                                     0, | ||||||
|  | @ -435,121 +432,19 @@ class ResultViewModel : ViewModel() { | ||||||
|                                     null, |                                     null, | ||||||
|                                     null, |                                     null, | ||||||
|                                     null, |                                     null, | ||||||
|  |                                     d.type, | ||||||
|  |                                     mainId | ||||||
|                                 ) |                                 ) | ||||||
|                             ), -1 |                             ), -1 | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else -> { |             else -> Unit | ||||||
|                 // nothing |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     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() |     private var _apiName: MutableLiveData<String> = MutableLiveData() | ||||||
|     val apiName: LiveData<String> get() = _apiName |     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.app.Activity | ||||||
| import android.widget.Toast | 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.DOWNLOAD_ACTION_PLAY_FILE | ||||||
| import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick | import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick | ||||||
| import com.lagradost.cloudstream3.ui.download.DownloadClickEvent | 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.APIHolder.restrictedApis | ||||||
| import com.lagradost.cloudstream3.AcraApplication | import com.lagradost.cloudstream3.AcraApplication | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey | 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.DubStatus | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.setLocale |  | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.showToast |  | ||||||
| import com.lagradost.cloudstream3.R | import com.lagradost.cloudstream3.R | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | @ -452,7 +452,7 @@ class SettingsFragment : PreferenceFragmentCompat() { | ||||||
| 
 | 
 | ||||||
|             val currentQuality = |             val currentQuality = | ||||||
|                 settingsManager.getInt( |                 settingsManager.getInt( | ||||||
|                     getString(R.string.watch_quality_pref), |                     getString(R.string.quality_pref_key), | ||||||
|                     Qualities.values().last().value |                     Qualities.values().last().value | ||||||
|                 ) |                 ) | ||||||
| 
 | 
 | ||||||
|  | @ -462,7 +462,7 @@ class SettingsFragment : PreferenceFragmentCompat() { | ||||||
|                 getString(R.string.watch_quality_pref), |                 getString(R.string.watch_quality_pref), | ||||||
|                 true, |                 true, | ||||||
|                 {}) { |                 {}) { | ||||||
|                 settingsManager.edit().putInt(getString(R.string.watch_quality_pref), prefValues[it]) |                 settingsManager.edit().putInt(getString(R.string.quality_pref_key), prefValues[it]) | ||||||
|                     .apply() |                     .apply() | ||||||
|             } |             } | ||||||
|             return@setOnPreferenceClickListener true |             return@setOnPreferenceClickListener true | ||||||
|  |  | ||||||
|  | @ -21,8 +21,9 @@ import com.google.android.exoplayer2.ui.CaptionStyleCompat | ||||||
| import com.jaredrummler.android.colorpicker.ColorPickerDialog | import com.jaredrummler.android.colorpicker.ColorPickerDialog | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.getKey | import com.lagradost.cloudstream3.AcraApplication.Companion.getKey | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | ||||||
| import com.lagradost.cloudstream3.MainActivity | import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.showToast | import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent | ||||||
|  | import com.lagradost.cloudstream3.CommonActivity.showToast | ||||||
| import com.lagradost.cloudstream3.R | import com.lagradost.cloudstream3.R | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.setKey | import com.lagradost.cloudstream3.utils.DataStore.setKey | ||||||
| import com.lagradost.cloudstream3.utils.Event | import com.lagradost.cloudstream3.utils.Event | ||||||
|  | @ -138,8 +139,7 @@ class SubtitlesFragment : Fragment() { | ||||||
|             2 -> state.backgroundColor = realColor |             2 -> state.backgroundColor = realColor | ||||||
|             3 -> state.windowColor = realColor |             3 -> state.windowColor = realColor | ||||||
| 
 | 
 | ||||||
|             else -> { |             else -> Unit | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         updateState() |         updateState() | ||||||
|     } |     } | ||||||
|  | @ -174,14 +174,14 @@ class SubtitlesFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|     override fun onDestroy() { |     override fun onDestroy() { | ||||||
|         super.onDestroy() |         super.onDestroy() | ||||||
|         MainActivity.onColorSelectedEvent -= ::onColorSelected |         onColorSelectedEvent -= ::onColorSelected | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||||||
|         super.onViewCreated(view, savedInstanceState) |         super.onViewCreated(view, savedInstanceState) | ||||||
|         hide = arguments?.getBoolean("hide") ?: true |         hide = arguments?.getBoolean("hide") ?: true | ||||||
|         MainActivity.onColorSelectedEvent += ::onColorSelected |         onColorSelectedEvent += ::onColorSelected | ||||||
|         MainActivity.onDialogDismissedEvent += ::onDialogDismissed |         onDialogDismissedEvent += ::onDialogDismissed | ||||||
| 
 | 
 | ||||||
|         context?.fixPaddingStatusbar(subs_root) |         context?.fixPaddingStatusbar(subs_root) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import android.content.ContentValues | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.content.Intent | import android.content.Intent | ||||||
| import android.content.pm.PackageManager | import android.content.pm.PackageManager | ||||||
|  | import android.database.Cursor | ||||||
| import android.media.AudioAttributes | import android.media.AudioAttributes | ||||||
| import android.media.AudioFocusRequest | import android.media.AudioFocusRequest | ||||||
| import android.media.AudioManager | import android.media.AudioManager | ||||||
|  | @ -13,17 +14,27 @@ import android.net.ConnectivityManager | ||||||
| import android.net.NetworkCapabilities | import android.net.NetworkCapabilities | ||||||
| import android.net.Uri | import android.net.Uri | ||||||
| import android.os.Build | import android.os.Build | ||||||
|  | import android.os.Environment | ||||||
|  | import android.os.ParcelFileDescriptor | ||||||
| import android.provider.MediaStore | import android.provider.MediaStore | ||||||
|  | import android.util.Log | ||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
| import com.google.android.gms.cast.framework.CastContext | import com.google.android.gms.cast.framework.CastContext | ||||||
| import com.google.android.gms.cast.framework.CastState | import com.google.android.gms.cast.framework.CastState | ||||||
| import com.google.android.gms.common.ConnectionResult | import com.google.android.gms.common.ConnectionResult | ||||||
| import com.google.android.gms.common.GoogleApiAvailability | import com.google.android.gms.common.GoogleApiAvailability | ||||||
| import com.google.android.gms.common.wrappers.Wrappers | 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.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.ui.result.ResultFragment | 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 com.lagradost.cloudstream3.utils.UIHelper.navigate | ||||||
|  | import okhttp3.Cache | ||||||
|  | import java.io.* | ||||||
| import java.net.URL | import java.net.URL | ||||||
| import java.net.URLDecoder | import java.net.URLDecoder | ||||||
| 
 | 
 | ||||||
|  | @ -59,7 +70,7 @@ object AppUtils { | ||||||
|                 ) |                 ) | ||||||
|             else |             else | ||||||
|                 startActivity(intent) |                 startActivity(intent) | ||||||
|         } catch (e : Exception) { |         } catch (e: Exception) { | ||||||
|             logError(e) |             logError(e) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -114,6 +125,13 @@ object AppUtils { | ||||||
|         return "" |         return "" | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fun Activity?.loadCache() { | ||||||
|  |         try { | ||||||
|  |             cacheClass("android.net.NetworkCapabilities".load()) | ||||||
|  |         } catch (_: Exception) { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     //private val viewModel: ResultViewModel by activityViewModels() |     //private val viewModel: ResultViewModel by activityViewModels() | ||||||
| 
 | 
 | ||||||
|     fun AppCompatActivity.loadResult( |     fun AppCompatActivity.loadResult( | ||||||
|  | @ -197,6 +215,96 @@ object AppUtils { | ||||||
|         return false |         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 { |     fun Context.isUsingMobileData(): Boolean { | ||||||
|         val conManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager |         val conManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager | ||||||
|         val networkInfo = conManager.allNetworks |         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 { |     fun Context.isAppInstalled(uri: String): Boolean { | ||||||
|         val pm = Wrappers.packageManager(this) |         val pm = Wrappers.packageManager(this) | ||||||
|         var appInstalled = false |         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.cast.framework.media.RemoteMediaClient | ||||||
| import com.google.android.gms.common.api.PendingResult | import com.google.android.gms.common.api.PendingResult | ||||||
| import com.google.android.gms.common.images.WebImage | 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.MetadataHolder | ||||||
|  | import com.lagradost.cloudstream3.ui.player.SubtitleData | ||||||
| import com.lagradost.cloudstream3.ui.result.ResultEpisode | import com.lagradost.cloudstream3.ui.result.ResultEpisode | ||||||
| import com.lagradost.cloudstream3.utils.Coroutines.main | import com.lagradost.cloudstream3.utils.Coroutines.main | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
|  | @ -28,7 +27,7 @@ object CastHelper { | ||||||
|         holder: MetadataHolder, |         holder: MetadataHolder, | ||||||
|         index: Int, |         index: Int, | ||||||
|         data: JSONObject?, |         data: JSONObject?, | ||||||
|         subtitles: List<SubtitleFile> |         subtitles: List<SubtitleData> | ||||||
|     ): MediaInfo { |     ): MediaInfo { | ||||||
|         val link = holder.currentLinks[index] |         val link = holder.currentLinks[index] | ||||||
|         val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) |         val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) | ||||||
|  | @ -50,9 +49,9 @@ object CastHelper { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         var subIndex = 0 |         var subIndex = 0 | ||||||
|         val tracks = sortSubs(subtitles).map { |         val tracks = subtitles.map { | ||||||
|             MediaTrack.Builder(subIndex++.toLong(), MediaTrack.TYPE_TEXT) |             MediaTrack.Builder(subIndex++.toLong(), MediaTrack.TYPE_TEXT) | ||||||
|                 .setName(it.lang) |                 .setName(it.name) | ||||||
|                 .setSubtype(MediaTrack.SUBTYPE_SUBTITLES) |                 .setSubtype(MediaTrack.SUBTYPE_SUBTITLES) | ||||||
|                 .setContentId(it.url) |                 .setContentId(it.url) | ||||||
|                 .build() |                 .build() | ||||||
|  | @ -79,9 +78,7 @@ object CastHelper { | ||||||
|                     callback.invoke(true) |                     callback.invoke(true) | ||||||
|                     println("FAILED AND LOAD NEXT") |                     println("FAILED AND LOAD NEXT") | ||||||
|                 } |                 } | ||||||
|                 else -> { |                 else -> Unit //IDK DO SMTH HERE | ||||||
|                     //IDK DO SMTH HERE |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -94,7 +91,7 @@ object CastHelper { | ||||||
|         currentEpisodeIndex: Int, |         currentEpisodeIndex: Int, | ||||||
|         episodes: List<ResultEpisode>, |         episodes: List<ResultEpisode>, | ||||||
|         currentLinks: List<ExtractorLink>, |         currentLinks: List<ExtractorLink>, | ||||||
|         subtitles: List<SubtitleFile>, |         subtitles: List<SubtitleData>, | ||||||
|         startIndex: Int? = null, |         startIndex: Int? = null, | ||||||
|         startTime: Long? = null, |         startTime: Long? = null, | ||||||
|     ): Boolean { |     ): Boolean { | ||||||
|  |  | ||||||
|  | @ -123,7 +123,8 @@ object DataStoreHelper { | ||||||
|         setKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), PosDur(pos, dur)) |         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) |         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 -> { |                     VideoDownloadManager.DownloadType.IsDone, VideoDownloadManager.DownloadType.IsFailed, VideoDownloadManager.DownloadType.IsStopped -> { | ||||||
|                         isDone = true |                         isDone = true | ||||||
|                     } |                     } | ||||||
|                     else -> { |                     else -> Unit | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| package com.lagradost.cloudstream3.utils | package com.lagradost.cloudstream3.utils | ||||||
| 
 | 
 | ||||||
|  | import android.net.Uri | ||||||
|  | import com.lagradost.cloudstream3.TvType | ||||||
| import com.lagradost.cloudstream3.USER_AGENT | import com.lagradost.cloudstream3.USER_AGENT | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.extractors.* | import com.lagradost.cloudstream3.extractors.* | ||||||
|  | @ -16,6 +18,22 @@ data class ExtractorLink( | ||||||
|     override val headers: Map<String, String> = mapOf() |     override val headers: Map<String, String> = mapOf() | ||||||
| ) : VideoDownloadManager.IDownloadableMinimum | ) : 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( | data class ExtractorSubtitleLink( | ||||||
|     val name: String, |     val name: String, | ||||||
|     override val url: String, |     override val url: String, | ||||||
|  | @ -133,8 +151,7 @@ fun getPostForm(requestUrl : String, html : String) : String? { | ||||||
|             "id" -> id = value |             "id" -> id = value | ||||||
|             "mode" -> mode = value |             "mode" -> mode = value | ||||||
|             "hash" -> hash = value |             "hash" -> hash = value | ||||||
|             else -> { |             else -> Unit | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (op == null || id == null || mode == null || hash == null) { |     if (op == null || id == null || mode == null || hash == null) { | ||||||
|  |  | ||||||
|  | @ -1,8 +1,11 @@ | ||||||
| package com.lagradost.cloudstream3.utils | package com.lagradost.cloudstream3.utils | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
|  | import com.lagradost.cloudstream3.utils.Coroutines.main | ||||||
| import org.jsoup.Jsoup | import org.jsoup.Jsoup | ||||||
|  | import java.lang.Thread.sleep | ||||||
| import java.util.* | import java.util.* | ||||||
|  | import kotlin.concurrent.thread | ||||||
| 
 | 
 | ||||||
| object FillerEpisodeCheck { | object FillerEpisodeCheck { | ||||||
|     private const val MAIN_URL = "https://www.animefillerlist.com" |     private const val MAIN_URL = "https://www.animefillerlist.com" | ||||||
|  | @ -50,6 +53,12 @@ object FillerEpisodeCheck { | ||||||
|         return false |         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>? { |     fun getFillerEpisodes(query: String): HashMap<Int, Boolean>? { | ||||||
|         try { |         try { | ||||||
|             if (!getFillerList()) return null |             if (!getFillerList()) return null | ||||||
|  | @ -87,4 +96,22 @@ object FillerEpisodeCheck { | ||||||
|             return null |             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.KotlinModule | ||||||
| import com.fasterxml.jackson.module.kotlin.readValue | import com.fasterxml.jackson.module.kotlin.readValue | ||||||
| import com.lagradost.cloudstream3.BuildConfig | 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.R | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||||
| import com.lagradost.cloudstream3.network.text |  | ||||||
| import java.io.File | import java.io.File | ||||||
| import kotlin.concurrent.thread | import kotlin.concurrent.thread | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,6 +72,7 @@ class JsUnpacker(packedJS: String?) { | ||||||
|         } |         } | ||||||
|         return null |         return null | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private inner class Unbase(private val radix: Int) { |     private inner class Unbase(private val radix: Int) { | ||||||
|         private val ALPHABET_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" |         private val ALPHABET_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||||||
|         private val ALPHABET_95 = |         private val ALPHABET_95 = | ||||||
|  | @ -90,6 +91,7 @@ class JsUnpacker(packedJS: String?) { | ||||||
|             } |             } | ||||||
|             return ret |             return ret | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         init { |         init { | ||||||
|             if (radix > 36) { |             if (radix > 36) { | ||||||
|                 when { |                 when { | ||||||
|  | @ -113,10 +115,102 @@ class JsUnpacker(packedJS: String?) { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @param  packedJS javascript P.A.C.K.E.R. coded. |      * @param  packedJS javascript P.A.C.K.E.R. coded. | ||||||
|      */ |      */ | ||||||
|     init { |     init { | ||||||
|         this.packedJS = packedJS |         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" | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |         android:tint="?attr/white" | ||||||
|         android:width="24dp" |         android:width="24dp" | ||||||
|         android:height="24dp" |         android:height="24dp" | ||||||
|         android:viewportWidth="850.39" |         android:viewportWidth="850.39" | ||||||
|         android:viewportHeight="850.39"> |         android:viewportHeight="850.39"> | ||||||
|     <path |     <path | ||||||
|             android:pathData="M267.01,189.64h99.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"/> |  | ||||||
|     <path |  | ||||||
|             android:pathData="M463.01,188.79h99.74v470.26h-99.74z" |  | ||||||
|             android:fillColor="#fff"/> |             android:fillColor="#fff"/> | ||||||
| </vector> | </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:layout_width="30dp" | ||||||
|                     android:background="?selectableItemBackgroundBorderless" |                     android:background="?selectableItemBackgroundBorderless" | ||||||
|                     android:src="@drawable/ic_baseline_play_arrow_24" |                     android:src="@drawable/ic_baseline_play_arrow_24" | ||||||
|                     android:tint="?attr/textColor" |                     app:tint="?attr/textColor" | ||||||
|                     android:contentDescription="@string/download"/> |                     android:contentDescription="@string/download"/> | ||||||
|         </FrameLayout> |         </FrameLayout> | ||||||
|     </GridLayout> |     </GridLayout> | ||||||
|  |  | ||||||
|  | @ -85,7 +85,6 @@ | ||||||
|                     android:visibility="visible" |                     android:visibility="visible" | ||||||
|             /> |             /> | ||||||
|             <ImageView |             <ImageView | ||||||
|                     android:tint="?attr/white" |  | ||||||
| 
 | 
 | ||||||
|                     android:visibility="visible" |                     android:visibility="visible" | ||||||
|                     android:layout_marginEnd="10dp" |                     android:layout_marginEnd="10dp" | ||||||
|  | @ -97,7 +96,8 @@ | ||||||
|                     android:id="@+id/download_header_episode_download" |                     android:id="@+id/download_header_episode_download" | ||||||
|                     android:background="?selectableItemBackgroundBorderless" |                     android:background="?selectableItemBackgroundBorderless" | ||||||
|                     android:src="@drawable/ic_baseline_play_arrow_24" |                     android:src="@drawable/ic_baseline_play_arrow_24" | ||||||
|                     android:contentDescription="@string/download"/> |                     android:contentDescription="@string/download" | ||||||
|  |                     app:tint="?attr/white" /> | ||||||
|         </FrameLayout> |         </FrameLayout> | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| </androidx.cardview.widget.CardView> | </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" |                             android:text="@string/continue_watching" | ||||||
|                     /> |                     /> | ||||||
|                     <ImageView |                     <ImageView | ||||||
|                             android:tint="?attr/textColor" |                             app:tint="?attr/textColor" | ||||||
|                             android:layout_marginEnd="5dp" |                             android:layout_marginEnd="5dp" | ||||||
|                             android:layout_gravity="end|center_vertical" |                             android:layout_gravity="end|center_vertical" | ||||||
|                             android:src="@drawable/ic_baseline_arrow_forward_24" |                             android:src="@drawable/ic_baseline_arrow_forward_24" | ||||||
|  | @ -451,7 +451,7 @@ | ||||||
|                         </LinearLayout> |                         </LinearLayout> | ||||||
|                     </HorizontalScrollView> |                     </HorizontalScrollView> | ||||||
|                     <ImageView |                     <ImageView | ||||||
|                             android:tint="?attr/textColor" |                             app:tint="?attr/textColor" | ||||||
|                             android:layout_marginEnd="5dp" |                             android:layout_marginEnd="5dp" | ||||||
|                             android:layout_gravity="end|center_vertical" |                             android:layout_gravity="end|center_vertical" | ||||||
|                             android:src="@drawable/ic_baseline_arrow_forward_24" |                             android:src="@drawable/ic_baseline_arrow_forward_24" | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
|         xmlns:tools="http://schemas.android.com/tools" |         xmlns:tools="http://schemas.android.com/tools" | ||||||
|         android:orientation="horizontal" |         android:orientation="horizontal" | ||||||
|         android:keepScreenOn="true" |         android:keepScreenOn="true" | ||||||
|  |         android:id="@+id/player_background" | ||||||
|         app:backgroundTint="@android:color/black" |         app:backgroundTint="@android:color/black" | ||||||
|         android:background="@android:color/black" |         android:background="@android:color/black" | ||||||
|         android:screenOrientation="sensorLandscape" |         android:screenOrientation="sensorLandscape" | ||||||
|  | @ -37,13 +38,14 @@ | ||||||
|             app:layout_constraintTop_toTopOf="parent" |             app:layout_constraintTop_toTopOf="parent" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="match_parent" |             android:layout_height="match_parent" | ||||||
|             android:id="@+id/loading_overlay" |             android:id="@+id/player_loading_overlay" | ||||||
|             android:background="@android:color/black" |             android:background="@android:color/black" | ||||||
|             android:backgroundTint="@android:color/black" |             android:backgroundTint="@android:color/black" | ||||||
|     > |     > | ||||||
| 
 | 
 | ||||||
|         <com.google.android.material.button.MaterialButton |         <com.google.android.material.button.MaterialButton | ||||||
|                 android:visibility="visible" |                 tools:visibility="visible" | ||||||
|  |                 android:visibility="gone" | ||||||
|                 android:layout_marginTop="70dp" |                 android:layout_marginTop="70dp" | ||||||
|                 android:layout_gravity="center" |                 android:layout_gravity="center" | ||||||
|                 app:cornerRadius="4dp" |                 app:cornerRadius="4dp" | ||||||
|  | @ -61,8 +63,6 @@ | ||||||
|                 android:layout_height="45dp"> |                 android:layout_height="45dp"> | ||||||
|         </com.google.android.material.button.MaterialButton> |         </com.google.android.material.button.MaterialButton> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         <ProgressBar |         <ProgressBar | ||||||
|                 android:layout_width="50dp" |                 android:layout_width="50dp" | ||||||
|                 android:layout_height="50dp" |                 android:layout_height="50dp" | ||||||
|  | @ -88,7 +88,7 @@ | ||||||
|             > |             > | ||||||
|             </ImageView> |             </ImageView> | ||||||
|             <ImageView |             <ImageView | ||||||
|                     android:id="@+id/video_go_back_holder" |                     android:id="@+id/player_loading_go_back" | ||||||
|                     android:layout_width="70dp" |                     android:layout_width="70dp" | ||||||
|                     android:layout_height="70dp" |                     android:layout_height="70dp" | ||||||
|                     android:layout_gravity="center" |                     android:layout_gravity="center" | ||||||
|  | @ -132,7 +132,7 @@ | ||||||
|                 android:textColor="@color/white" |                 android:textColor="@color/white" | ||||||
|                 android:id="@+id/video_torrent_seeders" |                 android:id="@+id/video_torrent_seeders" | ||||||
|                 tools:text="17 seeders" |                 tools:text="17 seeders" | ||||||
|                 app:layout_constraintTop_toBottomOf="@+id/video_title"> |                 app:layout_constraintTop_toBottomOf="@+id/player_video_title"> | ||||||
|         </TextView> |         </TextView> | ||||||
|     </FrameLayout> |     </FrameLayout> | ||||||
| </androidx.constraintlayout.widget.ConstraintLayout> | </androidx.constraintlayout.widget.ConstraintLayout> | ||||||
|  | @ -1,14 +1,13 @@ | ||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <FrameLayout | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|         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:layout_width="match_parent" | ||||||
|         android:id="@+id/result_root" |         android:id="@+id/result_root" | ||||||
|         android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" |         android:layout_height="match_parent" | ||||||
|         xmlns:tools="http://schemas.android.com/tools" |  | ||||||
|         android:background="?attr/primaryBlackBackground" |         android:background="?attr/primaryBlackBackground" | ||||||
|         android:clickable="true" |         android:clickable="true" | ||||||
|         android:focusable="true" |         android:focusable="true"> | ||||||
| > |  | ||||||
| 
 | 
 | ||||||
|     <com.facebook.shimmer.ShimmerFrameLayout |     <com.facebook.shimmer.ShimmerFrameLayout | ||||||
|             tools:visibility="gone" |             tools:visibility="gone" | ||||||
|  | @ -29,31 +28,44 @@ | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:orientation="vertical"> |                 android:orientation="vertical"> | ||||||
|  | 
 | ||||||
|             <LinearLayout |             <LinearLayout | ||||||
|                     android:layout_marginBottom="@dimen/loading_margin" |                     android:layout_marginBottom="@dimen/loading_margin" | ||||||
|                     android:orientation="horizontal" |                     android:orientation="horizontal" | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="match_parent"> |                     android:layout_height="match_parent"> | ||||||
|                 <include layout="@layout/loading_poster"/> | 
 | ||||||
|  |                 <include layout="@layout/loading_poster" /> | ||||||
|  | 
 | ||||||
|                 <LinearLayout |                 <LinearLayout | ||||||
|                         android:layout_marginStart="@dimen/loading_margin" |                         android:layout_marginStart="@dimen/loading_margin" | ||||||
|                         android:layout_marginEnd="@dimen/loading_margin" |                         android:layout_marginEnd="@dimen/loading_margin" | ||||||
|                         android:orientation="vertical" |                         android:orientation="vertical" | ||||||
|                         android:layout_width="match_parent" |                         android:layout_width="match_parent" | ||||||
|                         android:layout_height="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"/> |                     <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_short" /> | ||||||
|                 </LinearLayout> |                 </LinearLayout> | ||||||
|             </LinearLayout> |             </LinearLayout> | ||||||
| 
 | 
 | ||||||
|             <ImageView android:layout_width="match_parent" android:layout_height="20dp" |             <ImageView | ||||||
|                        tools:ignore="ContentDescription"/> |                     android:layout_width="match_parent" | ||||||
|             <include layout="@layout/loading_episode"/> |                     android:layout_height="20dp" | ||||||
|             <include layout="@layout/loading_episode"/> |                     tools:ignore="ContentDescription" /> | ||||||
|             <include layout="@layout/loading_episode"/> | 
 | ||||||
|  |             <include layout="@layout/loading_episode" /> | ||||||
|  | 
 | ||||||
|  |             <include layout="@layout/loading_episode" /> | ||||||
|  | 
 | ||||||
|  |             <include layout="@layout/loading_episode" /> | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|     </com.facebook.shimmer.ShimmerFrameLayout> |     </com.facebook.shimmer.ShimmerFrameLayout> | ||||||
|     <!--<ProgressBar |     <!--<ProgressBar | ||||||
|  | @ -72,6 +84,7 @@ | ||||||
|             android:layout_gravity="center" |             android:layout_gravity="center" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="wrap_content"> |             android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|         <com.google.android.material.button.MaterialButton |         <com.google.android.material.button.MaterialButton | ||||||
|                 android:layout_gravity="center" |                 android:layout_gravity="center" | ||||||
|                 style="@style/WhiteButton" |                 style="@style/WhiteButton" | ||||||
|  | @ -82,8 +95,8 @@ | ||||||
|                 android:text="@string/reload_error" |                 android:text="@string/reload_error" | ||||||
|                 android:id="@+id/result_reload_connectionerror" |                 android:id="@+id/result_reload_connectionerror" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_width="wrap_content" | ||||||
|                 android:minWidth="200dp" |                 android:minWidth="200dp" /> | ||||||
|         /> | 
 | ||||||
|         <com.google.android.material.button.MaterialButton |         <com.google.android.material.button.MaterialButton | ||||||
|                 android:layout_gravity="center" |                 android:layout_gravity="center" | ||||||
|                 style="@style/BlackButton" |                 style="@style/BlackButton" | ||||||
|  | @ -94,8 +107,8 @@ | ||||||
|                 android:text="@string/result_open_in_browser" |                 android:text="@string/result_open_in_browser" | ||||||
|                 android:id="@+id/result_reload_connection_open_in_browser" |                 android:id="@+id/result_reload_connection_open_in_browser" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_width="wrap_content" | ||||||
|                 android:minWidth="200dp" |                 android:minWidth="200dp" /> | ||||||
|         /> | 
 | ||||||
|         <TextView |         <TextView | ||||||
|                 android:layout_margin="5dp" |                 android:layout_margin="5dp" | ||||||
|                 android:gravity="center" |                 android:gravity="center" | ||||||
|  | @ -103,8 +116,7 @@ | ||||||
|                 android:id="@+id/result_error_text" |                 android:id="@+id/result_error_text" | ||||||
|                 android:textColor="?attr/textColor" |                 android:textColor="?attr/textColor" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content"> |                 android:layout_height="wrap_content" /> | ||||||
|         </TextView> |  | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| 
 | 
 | ||||||
|     <FrameLayout |     <FrameLayout | ||||||
|  | @ -120,6 +132,7 @@ | ||||||
|                 android:visibility="visible" |                 android:visibility="visible" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="230dp"> |                 android:layout_height="230dp"> | ||||||
|  | 
 | ||||||
|             <ImageView |             <ImageView | ||||||
|                     android:id="@+id/result_poster_blur" |                     android:id="@+id/result_poster_blur" | ||||||
| 
 | 
 | ||||||
|  | @ -129,31 +142,36 @@ | ||||||
|                     android:alpha="0" |                     android:alpha="0" | ||||||
|                     tools:src="@drawable/example_poster" |                     tools:src="@drawable/example_poster" | ||||||
|                     android:background="?attr/primaryGrayBackground" |                     android:background="?attr/primaryGrayBackground" | ||||||
|                     tools:ignore="ContentDescription"/> |                     tools:ignore="ContentDescription" /> | ||||||
|  | 
 | ||||||
|             <ImageView |             <ImageView | ||||||
|                     android:src="@drawable/background_shadow" |                     android:src="@drawable/background_shadow" | ||||||
|                     android:layout_gravity="bottom" |                     android:layout_gravity="bottom" | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="30dp" |                     android:layout_height="30dp" | ||||||
|                     tools:ignore="ContentDescription"/> |                     tools:ignore="ContentDescription" /> | ||||||
|         </FrameLayout> |         </FrameLayout> | ||||||
|  | 
 | ||||||
|         <androidx.core.widget.NestedScrollView |         <androidx.core.widget.NestedScrollView | ||||||
|                 android:id="@+id/result_scroll" |                 android:id="@+id/result_scroll" | ||||||
|                 android:background="?attr/primaryGrayBackground" |                 android:background="?attr/primaryGrayBackground" | ||||||
| 
 | 
 | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content"> |                 android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|             <LinearLayout |             <LinearLayout | ||||||
|                     android:background="?attr/primaryBlackBackground" |                     android:background="?attr/primaryBlackBackground" | ||||||
|                     android:orientation="vertical" |                     android:orientation="vertical" | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="match_parent"> |                     android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|                 <FrameLayout |                 <FrameLayout | ||||||
|                         android:background="?attr/primaryGrayBackground" |                         android:background="?attr/primaryGrayBackground" | ||||||
|                         android:paddingStart="@dimen/result_padding" |                         android:paddingStart="@dimen/result_padding" | ||||||
|                         android:paddingEnd="@dimen/result_padding" |                         android:paddingEnd="@dimen/result_padding" | ||||||
|                         android:layout_width="match_parent" |                         android:layout_width="match_parent" | ||||||
|                         android:layout_height="wrap_content"> |                         android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|                     <ImageView |                     <ImageView | ||||||
|                             android:nextFocusDown="@id/result_bookmark_button" |                             android:nextFocusDown="@id/result_bookmark_button" | ||||||
|                             android:nextFocusRight="@id/result_share" |                             android:nextFocusRight="@id/result_share" | ||||||
|  | @ -166,17 +184,17 @@ | ||||||
|                             android:layout_width="30dp" |                             android:layout_width="30dp" | ||||||
|                             android:layout_height="30dp" |                             android:layout_height="30dp" | ||||||
|                             android:layout_gravity="center_vertical|start" |                             android:layout_gravity="center_vertical|start" | ||||||
|                             android:tint="?attr/white" |  | ||||||
|                             android:src="@drawable/ic_baseline_arrow_back_24" |                             android:src="@drawable/ic_baseline_arrow_back_24" | ||||||
|                             android:contentDescription="@string/result_go_back"> |                             android:contentDescription="@string/go_back" | ||||||
|                     </ImageView> |                             app:tint="?attr/white" /> | ||||||
|  | 
 | ||||||
|                     <LinearLayout |                     <LinearLayout | ||||||
|                             android:gravity="end" |                             android:gravity="end" | ||||||
|                             android:layout_width="match_parent" |                             android:layout_width="match_parent" | ||||||
|                             android:layout_height="50dp" |                             android:layout_height="50dp" | ||||||
|                             android:id="@+id/media_route_button_holder" |                             android:id="@+id/media_route_button_holder" | ||||||
|                             android:layout_gravity="center_vertical|end" |                             android:layout_gravity="center_vertical|end"> | ||||||
|                     > | 
 | ||||||
|                         <androidx.mediarouter.app.MediaRouteButton |                         <androidx.mediarouter.app.MediaRouteButton | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:id="@+id/media_route_button" |                                 android:id="@+id/media_route_button" | ||||||
|  | @ -184,8 +202,8 @@ | ||||||
|                                 android:layout_height="50dp" |                                 android:layout_height="50dp" | ||||||
|                                 android:mediaRouteTypes="user" |                                 android:mediaRouteTypes="user" | ||||||
|                                 android:visibility="gone" |                                 android:visibility="gone" | ||||||
|                                 app:mediaRouteButtonTint="?attr/textColor" |                                 app:mediaRouteButtonTint="?attr/textColor" /> | ||||||
|                         /> | 
 | ||||||
|                         <ImageView |                         <ImageView | ||||||
|                                 android:visibility="gone" |                                 android:visibility="gone" | ||||||
|                                 android:nextFocusUp="@id/result_back" |                                 android:nextFocusUp="@id/result_back" | ||||||
|  | @ -196,16 +214,14 @@ | ||||||
|                                 android:id="@+id/result_add_sync" |                                 android:id="@+id/result_add_sync" | ||||||
|                                 android:layout_width="30dp" |                                 android:layout_width="30dp" | ||||||
|                                 android:layout_height="30dp" |                                 android:layout_height="30dp" | ||||||
|                                 android:layout_marginRight="10dp" |                                 android:layout_marginEnd="10dp" | ||||||
|                                 android:elevation="10dp" |                                 android:elevation="10dp" | ||||||
| 
 | 
 | ||||||
|                                 android:tint="?attr/textColor" |  | ||||||
| 
 |  | ||||||
|                                 android:background="?android:attr/selectableItemBackgroundBorderless" |                                 android:background="?android:attr/selectableItemBackgroundBorderless" | ||||||
|                                 android:src="@drawable/ic_baseline_add_24" |                                 android:src="@drawable/ic_baseline_add_24" | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:contentDescription="@string/add_sync"> |                                 android:contentDescription="@string/add_sync" | ||||||
|                         </ImageView> |                                 app:tint="?attr/textColor" /> | ||||||
| 
 | 
 | ||||||
|                         <ImageView |                         <ImageView | ||||||
|                                 android:nextFocusUp="@id/result_back" |                                 android:nextFocusUp="@id/result_back" | ||||||
|  | @ -216,16 +232,15 @@ | ||||||
|                                 android:id="@+id/result_share" |                                 android:id="@+id/result_share" | ||||||
|                                 android:layout_width="25dp" |                                 android:layout_width="25dp" | ||||||
|                                 android:layout_height="25dp" |                                 android:layout_height="25dp" | ||||||
|                                 android:layout_marginRight="10dp" |                                 android:layout_marginEnd="10dp" | ||||||
|                                 android:elevation="10dp" |                                 android:elevation="10dp" | ||||||
| 
 | 
 | ||||||
|                                 android:tint="?attr/textColor" |  | ||||||
| 
 |  | ||||||
|                                 android:background="?android:attr/selectableItemBackgroundBorderless" |                                 android:background="?android:attr/selectableItemBackgroundBorderless" | ||||||
|                                 android:src="@drawable/ic_outline_share_24" |                                 android:src="@drawable/ic_outline_share_24" | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:contentDescription="@string/result_share"> |                                 android:contentDescription="@string/result_share" | ||||||
|                         </ImageView> |                                 app:tint="?attr/textColor" /> | ||||||
|  | 
 | ||||||
|                         <ImageView |                         <ImageView | ||||||
|                                 android:nextFocusUp="@id/result_back" |                                 android:nextFocusUp="@id/result_back" | ||||||
|                                 android:nextFocusDown="@id/result_descript" |                                 android:nextFocusDown="@id/result_descript" | ||||||
|  | @ -238,13 +253,11 @@ | ||||||
|                                 android:layout_margin="5dp" |                                 android:layout_margin="5dp" | ||||||
|                                 android:elevation="10dp" |                                 android:elevation="10dp" | ||||||
| 
 | 
 | ||||||
|                                 android:tint="?attr/textColor" |  | ||||||
| 
 |  | ||||||
|                                 android:background="?android:attr/selectableItemBackgroundBorderless" |                                 android:background="?android:attr/selectableItemBackgroundBorderless" | ||||||
|                                 android:src="@drawable/ic_baseline_public_24" |                                 android:src="@drawable/ic_baseline_public_24" | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:contentDescription="@string/result_open_in_browser"> |                                 android:contentDescription="@string/result_open_in_browser" | ||||||
|                         </ImageView> |                                 app:tint="?attr/textColor" /> | ||||||
| 
 | 
 | ||||||
|                         <ImageView |                         <ImageView | ||||||
|                                 android:nextFocusUp="@id/result_back" |                                 android:nextFocusUp="@id/result_back" | ||||||
|  | @ -258,15 +271,14 @@ | ||||||
|                                 android:layout_margin="5dp" |                                 android:layout_margin="5dp" | ||||||
|                                 android:elevation="10dp" |                                 android:elevation="10dp" | ||||||
| 
 | 
 | ||||||
|                                 android:tint="?attr/textColor" |  | ||||||
| 
 |  | ||||||
|                                 android:background="?android:attr/selectableItemBackgroundBorderless" |                                 android:background="?android:attr/selectableItemBackgroundBorderless" | ||||||
|                                 android:src="@drawable/search_icon" |                                 android:src="@drawable/search_icon" | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:contentDescription="@string/result_open_in_browser"> |                                 android:contentDescription="@string/result_open_in_browser" | ||||||
|                         </ImageView> |                                 app:tint="?attr/textColor" /> | ||||||
|                     </LinearLayout> |                     </LinearLayout> | ||||||
|                 </FrameLayout> |                 </FrameLayout> | ||||||
|  | 
 | ||||||
|                 <LinearLayout |                 <LinearLayout | ||||||
|                         android:clipToPadding="false" |                         android:clipToPadding="false" | ||||||
|                         android:orientation="vertical" |                         android:orientation="vertical" | ||||||
|  | @ -274,6 +286,7 @@ | ||||||
|                         android:paddingEnd="@dimen/result_padding" |                         android:paddingEnd="@dimen/result_padding" | ||||||
|                         android:layout_width="match_parent" |                         android:layout_width="match_parent" | ||||||
|                         android:layout_height="match_parent"> |                         android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|                     <LinearLayout |                     <LinearLayout | ||||||
|                             android:visibility="visible" |                             android:visibility="visible" | ||||||
|                             android:layout_marginBottom="15dp" |                             android:layout_marginBottom="15dp" | ||||||
|  | @ -281,11 +294,13 @@ | ||||||
|                             android:orientation="horizontal" |                             android:orientation="horizontal" | ||||||
|                             android:layout_width="match_parent" |                             android:layout_width="match_parent" | ||||||
|                             android:layout_height="wrap_content"> |                             android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|                         <androidx.cardview.widget.CardView |                         <androidx.cardview.widget.CardView | ||||||
|                                 android:id="@+id/result_poster_holder" |                                 android:id="@+id/result_poster_holder" | ||||||
|                                 app:cardCornerRadius="@dimen/rounded_image_radius" |                                 app:cardCornerRadius="@dimen/rounded_image_radius" | ||||||
|                                 android:layout_width="100dp" |                                 android:layout_width="100dp" | ||||||
|                                 android:layout_height="140dp"> |                                 android:layout_height="140dp"> | ||||||
|  | 
 | ||||||
|                             <ImageView |                             <ImageView | ||||||
|                                     android:foreground="@drawable/outline_drawable" |                                     android:foreground="@drawable/outline_drawable" | ||||||
| 
 | 
 | ||||||
|  | @ -294,13 +309,15 @@ | ||||||
|                                     android:layout_width="match_parent" |                                     android:layout_width="match_parent" | ||||||
|                                     android:layout_height="match_parent" |                                     android:layout_height="match_parent" | ||||||
|                                     tools:src="@drawable/example_poster" |                                     tools:src="@drawable/example_poster" | ||||||
|                                     android:contentDescription="@string/result_poster_img_des"/> |                                     android:contentDescription="@string/result_poster_img_des" /> | ||||||
|                         </androidx.cardview.widget.CardView> |                         </androidx.cardview.widget.CardView> | ||||||
|  | 
 | ||||||
|                         <LinearLayout |                         <LinearLayout | ||||||
|                                 android:layout_marginStart="10dp" |                                 android:layout_marginStart="10dp" | ||||||
|                                 android:orientation="vertical" |                                 android:orientation="vertical" | ||||||
|                                 android:layout_width="match_parent" |                                 android:layout_width="match_parent" | ||||||
|                                 android:layout_height="match_parent"> |                                 android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|                             <TextView |                             <TextView | ||||||
|                                     android:maxLines="2" |                                     android:maxLines="2" | ||||||
|                                     android:layout_marginBottom="10dp" |                                     android:layout_marginBottom="10dp" | ||||||
|  | @ -308,27 +325,20 @@ | ||||||
|                                     tools:text="The Perfect Run The Perfect Run The Perfect Run" |                                     tools:text="The Perfect Run The Perfect Run The Perfect Run" | ||||||
|                                     android:textSize="20sp" |                                     android:textSize="20sp" | ||||||
|                                     android:textStyle="bold" |                                     android:textStyle="bold" | ||||||
|                                     android:textColor="?attr/textColor" android:layout_width="wrap_content" |                                     android:textColor="?attr/textColor" | ||||||
|                                     android:layout_height="wrap_content"> |                                     android:layout_width="wrap_content" | ||||||
|                             </TextView> |                                     android:layout_height="wrap_content" /> | ||||||
|  | 
 | ||||||
|                             <LinearLayout |                             <LinearLayout | ||||||
|                                     android:layout_width="match_parent" |                                     android:layout_width="match_parent" | ||||||
|                                     android:layout_height="wrap_content"> |                                     android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|                                 <com.google.android.material.button.MaterialButton |                                 <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:id="@+id/result_meta_site" | ||||||
|                                         android:layout_marginEnd="0dp" |                                         style="@style/SmallBlackButton" | ||||||
|                                         android:layout_marginStart="0dp" |                                         android:layout_gravity="center_vertical" | ||||||
|                                         android:textSize="12sp" |                                         tools:text="Gogoanime" /> | ||||||
|                                         android:layout_width="wrap_content" | 
 | ||||||
|                                         android:layout_height="24dp"> |  | ||||||
|                                 </com.google.android.material.button.MaterialButton> |  | ||||||
|                                 <TextView |                                 <TextView | ||||||
|                                         android:id="@+id/result_meta_year" |                                         android:id="@+id/result_meta_year" | ||||||
|                                         android:layout_marginStart="10dp" |                                         android:layout_marginStart="10dp" | ||||||
|  | @ -336,8 +346,8 @@ | ||||||
|                                         android:layout_gravity="center_vertical" |                                         android:layout_gravity="center_vertical" | ||||||
|                                         android:textColor="?attr/white" |                                         android:textColor="?attr/white" | ||||||
|                                         android:layout_width="wrap_content" |                                         android:layout_width="wrap_content" | ||||||
|                                         android:layout_height="wrap_content"> |                                         android:layout_height="wrap_content" /> | ||||||
|                                 </TextView> | 
 | ||||||
|                                 <TextView |                                 <TextView | ||||||
|                                         android:id="@+id/result_meta_rating" |                                         android:id="@+id/result_meta_rating" | ||||||
|                                         android:layout_marginStart="10dp" |                                         android:layout_marginStart="10dp" | ||||||
|  | @ -346,8 +356,8 @@ | ||||||
|                                         android:layout_gravity="center_vertical" |                                         android:layout_gravity="center_vertical" | ||||||
|                                         android:textColor="?attr/textColor" |                                         android:textColor="?attr/textColor" | ||||||
|                                         android:layout_width="wrap_content" |                                         android:layout_width="wrap_content" | ||||||
|                                         android:layout_height="wrap_content"> |                                         android:layout_height="wrap_content" /> | ||||||
|                                 </TextView> | 
 | ||||||
|                                 <TextView |                                 <TextView | ||||||
|                                         android:id="@+id/result_meta_duration" |                                         android:id="@+id/result_meta_duration" | ||||||
|                                         android:layout_marginStart="10dp" |                                         android:layout_marginStart="10dp" | ||||||
|  | @ -356,12 +366,13 @@ | ||||||
|                                         android:layout_gravity="center_vertical" |                                         android:layout_gravity="center_vertical" | ||||||
|                                         android:textColor="?attr/textColor" |                                         android:textColor="?attr/textColor" | ||||||
|                                         android:layout_width="wrap_content" |                                         android:layout_width="wrap_content" | ||||||
|                                         android:layout_height="wrap_content"> |                                         android:layout_height="wrap_content" /> | ||||||
|                                 </TextView> |  | ||||||
|                             </LinearLayout> |                             </LinearLayout> | ||||||
|  | 
 | ||||||
|                             <FrameLayout |                             <FrameLayout | ||||||
|                                     android:layout_width="match_parent" |                                     android:layout_width="match_parent" | ||||||
|                                     android:layout_height="match_parent"> |                                     android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|                                 <TextView |                                 <TextView | ||||||
|                                         android:textColor="?attr/textColor" |                                         android:textColor="?attr/textColor" | ||||||
|                                         android:foreground="@drawable/outline_drawable" |                                         android:foreground="@drawable/outline_drawable" | ||||||
|  | @ -374,17 +385,18 @@ | ||||||
|                                         android:textSize="15sp" |                                         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. " |                                         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_width="match_parent" | ||||||
|                                         android:layout_height="wrap_content"> |                                         android:layout_height="wrap_content" /> | ||||||
|                                 </TextView> | 
 | ||||||
|                                 <ImageView |                                 <ImageView | ||||||
|                                         android:src="@drawable/background_shadow" |                                         android:src="@drawable/background_shadow" | ||||||
|                                         android:layout_gravity="bottom" |                                         android:layout_gravity="bottom" | ||||||
|                                         android:layout_width="match_parent" |                                         android:layout_width="match_parent" | ||||||
|                                         android:layout_height="30dp" |                                         android:layout_height="30dp" | ||||||
|                                         tools:ignore="ContentDescription"/> |                                         tools:ignore="ContentDescription" /> | ||||||
|                             </FrameLayout> |                             </FrameLayout> | ||||||
|                         </LinearLayout> |                         </LinearLayout> | ||||||
|                     </LinearLayout> |                     </LinearLayout> | ||||||
|  | 
 | ||||||
|                     <com.google.android.material.button.MaterialButton |                     <com.google.android.material.button.MaterialButton | ||||||
|                             android:layout_marginTop="0dp" |                             android:layout_marginTop="0dp" | ||||||
|                             android:paddingTop="0dp" |                             android:paddingTop="0dp" | ||||||
|  | @ -405,9 +417,9 @@ | ||||||
|                             android:id="@+id/result_bookmark_button" |                             android:id="@+id/result_bookmark_button" | ||||||
|                             tools:text="Bookmark" |                             tools:text="Bookmark" | ||||||
|                             android:layout_width="wrap_content" |                             android:layout_width="wrap_content" | ||||||
|                             style="@style/BlackButton" |                             style="@style/BlackButton"> | ||||||
|                     > | 
 | ||||||
|                         <requestFocus/> |                         <requestFocus /> | ||||||
|                     </com.google.android.material.button.MaterialButton> |                     </com.google.android.material.button.MaterialButton> | ||||||
| 
 | 
 | ||||||
|                     <TextView |                     <TextView | ||||||
|  | @ -415,16 +427,18 @@ | ||||||
|                             android:id="@+id/result_vpn" |                             android:id="@+id/result_vpn" | ||||||
|                             android:textSize="15sp" |                             android:textSize="15sp" | ||||||
|                             tools:text="@string/vpn_torrent" |                             tools:text="@string/vpn_torrent" | ||||||
|                             android:layout_width="match_parent" android:layout_height="wrap_content"> |                             android:layout_width="match_parent" | ||||||
|                     </TextView> |                             android:layout_height="wrap_content" /> | ||||||
|  | 
 | ||||||
|                     <TextView |                     <TextView | ||||||
|                             android:layout_marginBottom="5dp" |                             android:layout_marginBottom="5dp" | ||||||
|                             android:textColor="?attr/grayTextColor" |                             android:textColor="?attr/grayTextColor" | ||||||
|                             android:id="@+id/result_info" |                             android:id="@+id/result_info" | ||||||
|                             android:textSize="15sp" |                             android:textSize="15sp" | ||||||
|                             tools:text="@string/provider_info_meta" |                             tools:text="@string/provider_info_meta" | ||||||
|                             android:layout_width="match_parent" android:layout_height="wrap_content"> |                             android:layout_width="match_parent" | ||||||
|                     </TextView> |                             android:layout_height="wrap_content" /> | ||||||
|  | 
 | ||||||
|                     <TextView |                     <TextView | ||||||
|                             android:visibility="gone" |                             android:visibility="gone" | ||||||
|                             android:id="@+id/result_tag_holder" |                             android:id="@+id/result_tag_holder" | ||||||
|  | @ -435,12 +449,12 @@ | ||||||
|                             android:layout_marginTop="10dp" |                             android:layout_marginTop="10dp" | ||||||
|                             android:layout_marginBottom="10dp" |                             android:layout_marginBottom="10dp" | ||||||
|                             android:textStyle="normal" |                             android:textStyle="normal" | ||||||
|                             android:textColor="?attr/textColor" |                             android:textColor="?attr/textColor" /> | ||||||
|                     /> | 
 | ||||||
|                     <com.lagradost.cloudstream3.widget.FlowLayout |                     <com.lagradost.cloudstream3.widget.FlowLayout | ||||||
|                             android:id="@+id/result_tag" |                             android:id="@+id/result_tag" | ||||||
|                             android:layout_width="match_parent" |                             android:layout_width="match_parent" | ||||||
|                             android:layout_height="wrap_content"/> |                             android:layout_height="wrap_content" /> | ||||||
| 
 | 
 | ||||||
|                     <LinearLayout |                     <LinearLayout | ||||||
|                             android:layout_marginTop="5dp" |                             android:layout_marginTop="5dp" | ||||||
|  | @ -448,6 +462,7 @@ | ||||||
|                             android:id="@+id/result_movie_parent" |                             android:id="@+id/result_movie_parent" | ||||||
|                             android:layout_width="match_parent" |                             android:layout_width="match_parent" | ||||||
|                             android:layout_height="wrap_content"> |                             android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|                         <com.google.android.material.button.MaterialButton |                         <com.google.android.material.button.MaterialButton | ||||||
|                                 android:layout_marginBottom="10dp" |                                 android:layout_marginBottom="10dp" | ||||||
|                                 android:nextFocusUp="@id/result_bookmark_button" |                                 android:nextFocusUp="@id/result_bookmark_button" | ||||||
|  | @ -461,8 +476,8 @@ | ||||||
|                                 android:layout_gravity="center_vertical" |                                 android:layout_gravity="center_vertical" | ||||||
|                                 android:text="@string/play_movie_button" |                                 android:text="@string/play_movie_button" | ||||||
|                                 app:icon="@drawable/ic_baseline_play_arrow_24" |                                 app:icon="@drawable/ic_baseline_play_arrow_24" | ||||||
|                                 android:layout_width="match_parent"> |                                 android:layout_width="match_parent" /> | ||||||
|                         </com.google.android.material.button.MaterialButton> | 
 | ||||||
|                         <com.google.android.material.button.MaterialButton |                         <com.google.android.material.button.MaterialButton | ||||||
|                                 android:nextFocusUp="@id/result_play_movie" |                                 android:nextFocusUp="@id/result_play_movie" | ||||||
|                                 android:nextFocusDown="@id/result_season_button" |                                 android:nextFocusDown="@id/result_season_button" | ||||||
|  | @ -479,8 +494,7 @@ | ||||||
| 
 | 
 | ||||||
|                                 android:clickable="true" |                                 android:clickable="true" | ||||||
|                                 android:focusable="true" |                                 android:focusable="true" | ||||||
|                                 android:layout_width="match_parent"> |                                 android:layout_width="match_parent" /> | ||||||
|                         </com.google.android.material.button.MaterialButton> |  | ||||||
| 
 | 
 | ||||||
|                         <androidx.core.widget.ContentLoadingProgressBar |                         <androidx.core.widget.ContentLoadingProgressBar | ||||||
|                                 android:layout_width="match_parent" |                                 android:layout_width="match_parent" | ||||||
|  | @ -493,7 +507,8 @@ | ||||||
|                                 android:layout_gravity="end|center_vertical" |                                 android:layout_gravity="end|center_vertical" | ||||||
|                                 android:progress="0" |                                 android:progress="0" | ||||||
|                                 android:visibility="gone" |                                 android:visibility="gone" | ||||||
|                                 tools:visibility="visible"/> |                                 tools:visibility="visible" /> | ||||||
|  | 
 | ||||||
|                         <TextView |                         <TextView | ||||||
|                                 android:id="@+id/result_movie_text_progress" |                                 android:id="@+id/result_movie_text_progress" | ||||||
|                                 android:layout_gravity="center_vertical" |                                 android:layout_gravity="center_vertical" | ||||||
|  | @ -501,8 +516,7 @@ | ||||||
|                                 tools:text="128MB / 237MB" |                                 tools:text="128MB / 237MB" | ||||||
|                                 android:textColor="?attr/grayTextColor" |                                 android:textColor="?attr/grayTextColor" | ||||||
|                                 android:layout_width="wrap_content" |                                 android:layout_width="wrap_content" | ||||||
|                                 android:layout_height="match_parent"> |                                 android:layout_height="match_parent" /> | ||||||
|                         </TextView> |  | ||||||
|                     </LinearLayout> |                     </LinearLayout> | ||||||
|                     <!--<TextView |                     <!--<TextView | ||||||
|                             android:visibility="gone" |                             android:visibility="gone" | ||||||
|  | @ -553,18 +567,21 @@ | ||||||
|                             app:spanCount="3" |                             app:spanCount="3" | ||||||
|                             android:id="@+id/result_recommendations" |                             android:id="@+id/result_recommendations" | ||||||
|                             tools:listitem="@layout/search_result_grid" |                             tools:listitem="@layout/search_result_grid" | ||||||
|                             android:orientation="vertical" |                             android:orientation="vertical" /> | ||||||
|                     /> | 
 | ||||||
|                     <LinearLayout |                     <LinearLayout | ||||||
|                             android:id="@+id/result_episodes_tab" |                             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"> |                             android:orientation="vertical"> | ||||||
|  | 
 | ||||||
|                         <LinearLayout |                         <LinearLayout | ||||||
|                                 android:layout_marginBottom="10dp" |                                 android:layout_marginBottom="10dp" | ||||||
|                                 android:orientation="horizontal" |                                 android:orientation="horizontal" | ||||||
|                                 android:gravity="center_vertical" |                                 android:gravity="center_vertical" | ||||||
|                                 android:layout_width="match_parent" |                                 android:layout_width="match_parent" | ||||||
|                                 android:layout_height="wrap_content"> |                                 android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|                             <com.google.android.material.button.MaterialButton |                             <com.google.android.material.button.MaterialButton | ||||||
|                                     tools:visibility="visible" |                                     tools:visibility="visible" | ||||||
|                                     tools:text="Season 1" |                                     tools:text="Season 1" | ||||||
|  | @ -577,8 +594,8 @@ | ||||||
|                                     android:visibility="gone" |                                     android:visibility="gone" | ||||||
|                                     android:layout_gravity="center_vertical" |                                     android:layout_gravity="center_vertical" | ||||||
|                                     android:layout_marginStart="0dp" |                                     android:layout_marginStart="0dp" | ||||||
|                                     style="@style/MultiSelectButton"> |                                     style="@style/MultiSelectButton" /> | ||||||
|                             </com.google.android.material.button.MaterialButton> | 
 | ||||||
|                             <com.google.android.material.button.MaterialButton |                             <com.google.android.material.button.MaterialButton | ||||||
|                                     tools:visibility="visible" |                                     tools:visibility="visible" | ||||||
|                                     tools:text="50-100" |                                     tools:text="50-100" | ||||||
|  | @ -592,8 +609,7 @@ | ||||||
|                                     android:visibility="gone" |                                     android:visibility="gone" | ||||||
|                                     android:layout_gravity="center_vertical" |                                     android:layout_gravity="center_vertical" | ||||||
|                                     android:layout_marginStart="0dp" |                                     android:layout_marginStart="0dp" | ||||||
|                                     style="@style/MultiSelectButton" |                                     style="@style/MultiSelectButton" /> | ||||||
|                             /> |  | ||||||
| 
 | 
 | ||||||
|                             <com.google.android.material.button.MaterialButton |                             <com.google.android.material.button.MaterialButton | ||||||
|                                     tools:visibility="visible" |                                     tools:visibility="visible" | ||||||
|  | @ -608,8 +624,8 @@ | ||||||
|                                     android:visibility="gone" |                                     android:visibility="gone" | ||||||
|                                     android:layout_gravity="center_vertical" |                                     android:layout_gravity="center_vertical" | ||||||
|                                     android:layout_marginStart="0dp" |                                     android:layout_marginStart="0dp" | ||||||
|                                     style="@style/MultiSelectButton" |                                     style="@style/MultiSelectButton" /> | ||||||
|                             /> | 
 | ||||||
|                             <TextView |                             <TextView | ||||||
|                                     android:layout_width="wrap_content" |                                     android:layout_width="wrap_content" | ||||||
|                                     android:layout_height="wrap_content" |                                     android:layout_height="wrap_content" | ||||||
|  | @ -619,18 +635,44 @@ | ||||||
|                                     android:layout_marginTop="10dp" |                                     android:layout_marginTop="10dp" | ||||||
|                                     android:layout_marginBottom="10dp" |                                     android:layout_marginBottom="10dp" | ||||||
|                                     android:textStyle="normal" |                                     android:textStyle="normal" | ||||||
|                                     android:textColor="?attr/textColor" |                                     android:textColor="?attr/textColor" /> | ||||||
|                             /> |  | ||||||
|                         </LinearLayout> |                         </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" |                                 android:id="@+id/result_episode_loading" | ||||||
| 
 | 
 | ||||||
|                                 style="@style/Widget.AppCompat.ProgressBar" |                                 style="@style/Widget.AppCompat.ProgressBar" | ||||||
|                                 android:layout_gravity="center" |                                 android:layout_gravity="center" | ||||||
|                                 android:layout_width="50dp" |                                 android:layout_width="50dp" | ||||||
|                                 android:layout_height="50dp"> |                                 android:layout_height="50dp" />--> | ||||||
|                         </androidx.core.widget.ContentLoadingProgressBar> | 
 | ||||||
|                         <androidx.recyclerview.widget.RecyclerView |                         <androidx.recyclerview.widget.RecyclerView | ||||||
|                                 android:descendantFocusability="afterDescendants" |                                 android:descendantFocusability="afterDescendants" | ||||||
|                                 android:id="@+id/result_episodes" |                                 android:id="@+id/result_episodes" | ||||||
|  | @ -639,26 +681,26 @@ | ||||||
|                                 android:paddingBottom="100dp" |                                 android:paddingBottom="100dp" | ||||||
|                                 tools:listitem="@layout/result_episode" |                                 tools:listitem="@layout/result_episode" | ||||||
|                                 android:layout_width="match_parent" |                                 android:layout_width="match_parent" | ||||||
|                                 android:layout_height="wrap_content" |                                 android:layout_height="wrap_content" /> | ||||||
|                         /> |  | ||||||
|                     </LinearLayout> |                     </LinearLayout> | ||||||
|                 </LinearLayout> |                 </LinearLayout> | ||||||
|             </LinearLayout> |             </LinearLayout> | ||||||
|         </androidx.core.widget.NestedScrollView> |         </androidx.core.widget.NestedScrollView> | ||||||
|  | 
 | ||||||
|         <LinearLayout |         <LinearLayout | ||||||
|                 android:layout_gravity="bottom" |                 android:layout_gravity="bottom" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:orientation="vertical" |                 android:orientation="vertical"> | ||||||
|         > | 
 | ||||||
|             <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton |             <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton | ||||||
|                     android:visibility="gone" |                     android:visibility="gone" | ||||||
|                     tools:visibility="visible" |                     tools:visibility="visible" | ||||||
|                     android:id="@+id/result_bookmark_fab" |                     android:id="@+id/result_bookmark_fab" | ||||||
|                     app:icon="@drawable/ic_baseline_bookmark_24" |                     app:icon="@drawable/ic_baseline_bookmark_24" | ||||||
|                     style="@style/ExtendedFloatingActionButton" |                     style="@style/ExtendedFloatingActionButton" | ||||||
|                     tools:ignore="ContentDescription"> |                     tools:ignore="ContentDescription" /> | ||||||
|             </com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton> | 
 | ||||||
|             <fragment |             <fragment | ||||||
|                     app:customCastBackgroundColor="?attr/primaryBlackBackground" |                     app:customCastBackgroundColor="?attr/primaryBlackBackground" | ||||||
|                     app:castControlButtons="@array/cast_mini_controller_control_buttons" |                     app:castControlButtons="@array/cast_mini_controller_control_buttons" | ||||||
|  | @ -667,8 +709,7 @@ | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|                     android:visibility="gone" |                     android:visibility="gone" | ||||||
|                     class="com.lagradost.cloudstream3.ui.MyMiniControllerFragment" |                     class="com.lagradost.cloudstream3.ui.MyMiniControllerFragment" | ||||||
|                     tools:ignore="FragmentTagUsage"> |                     tools:ignore="FragmentTagUsage" /> | ||||||
|             </fragment> |  | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|     </FrameLayout> |     </FrameLayout> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
|                 tools:text="Trending" |                 tools:text="Trending" | ||||||
|         /> |         /> | ||||||
|         <ImageView |         <ImageView | ||||||
|                 android:tint="?attr/textColor" |                 app:tint="?attr/textColor" | ||||||
|                 android:layout_marginEnd="5dp" |                 android:layout_marginEnd="5dp" | ||||||
|                 android:layout_gravity="end|center_vertical" |                 android:layout_gravity="end|center_vertical" | ||||||
|                 android:src="@drawable/ic_baseline_arrow_forward_24" |                 android:src="@drawable/ic_baseline_arrow_forward_24" | ||||||
|  |  | ||||||
|  | @ -1,24 +1,23 @@ | ||||||
| <FrameLayout | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|         xmlns:android="http://schemas.android.com/apk/res/android" |  | ||||||
|         xmlns:app="http://schemas.android.com/apk/res-auto" |         xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|         xmlns:tools="http://schemas.android.com/tools" |         xmlns:tools="http://schemas.android.com/tools" | ||||||
|  |         android:id="@+id/player_holder" | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="match_parent" |         android:layout_height="match_parent" | ||||||
|         android:orientation="vertical" |         android:orientation="vertical" | ||||||
|         android:id="@+id/player_holder" |  | ||||||
|         android:screenOrientation="landscape" |         android:screenOrientation="landscape" | ||||||
|         tools:orientation="vertical" |         tools:orientation="vertical"> | ||||||
| > | 
 | ||||||
|     <FrameLayout |     <FrameLayout | ||||||
|             android:id="@+id/subtitle_holder" |             android:id="@+id/subtitle_holder" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="match_parent"> |             android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|         <View |         <View | ||||||
|  |                 android:id="@+id/shadow_overlay" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="match_parent" |                 android:layout_height="match_parent" | ||||||
|                 android:id="@+id/shadow_overlay" |                 android:background="@color/black_overlay" /> | ||||||
|                 android:background="@color/black_overlay" |  | ||||||
|         /> |  | ||||||
|     </FrameLayout> |     </FrameLayout> | ||||||
| 
 | 
 | ||||||
|     <!-- |     <!-- | ||||||
|  | @ -56,602 +55,566 @@ | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| --> | --> | ||||||
|     <RelativeLayout |     <RelativeLayout | ||||||
|  |             android:id="@+id/player_time_menu" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="200dp" |             android:layout_height="200dp" | ||||||
|             android:id="@+id/timeMenu" |  | ||||||
|             android:orientation="horizontal" |             android:orientation="horizontal" | ||||||
|             app:layout_constraintTop_toBottomOf="@+id/topMenuRight" |             app:layout_constraintBottom_toTopOf="@+id/player_center_menu" | ||||||
|             app:layout_constraintBottom_toTopOf="@+id/centerMenu" |             app:layout_constraintTop_toBottomOf="@+id/topMenuRight"> | ||||||
|     > | 
 | ||||||
|         <TextView |         <TextView | ||||||
|  |                 android:id="@+id/player_time_text_left" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="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: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:alpha="0" | ||||||
|  |                 android:gravity="center|start" | ||||||
|                 android:shadowColor="@android:color/black" |                 android:shadowColor="@android:color/black" | ||||||
|                 android:shadowRadius="10.0" |                 android:shadowRadius="10.0" | ||||||
|                 android:textColor="@android:color/white" |                 android:textColor="@android:color/white" | ||||||
|         > |                 android:textSize="40sp"> | ||||||
| 
 | 
 | ||||||
|         </TextView> |         </TextView> | ||||||
|  | 
 | ||||||
|         <TextView |         <TextView | ||||||
|  |                 android:id="@+id/player_time_text" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="match_parent" |                 android:layout_height="match_parent" | ||||||
|                 android:id="@+id/timeTextRight" |                 android:gravity="center" | ||||||
|                 android:gravity="center|end" |  | ||||||
|                 android:layout_marginEnd="100dp" |  | ||||||
|                 android:textSize="40sp" |  | ||||||
|                 android:shadowColor="@android:color/black" |                 android:shadowColor="@android:color/black" | ||||||
|                 android:shadowRadius="10.0" |                 android:shadowRadius="10.0" | ||||||
|                 android:textColor="@android:color/white" |                 android:textColor="@android:color/white" | ||||||
|         > |                 android:textSize="30sp" | ||||||
|  |                 tools:text="+100"> | ||||||
|  | 
 | ||||||
|         </TextView> |         </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> |     </RelativeLayout> | ||||||
| 
 | 
 | ||||||
|     <androidx.constraintlayout.widget.ConstraintLayout |     <androidx.constraintlayout.widget.ConstraintLayout | ||||||
|  |             android:id="@+id/player_video_holder" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="match_parent" |             android:layout_height="match_parent"> | ||||||
|             android:id="@+id/video_holder" | 
 | ||||||
|     > |  | ||||||
|         <FrameLayout |         <FrameLayout | ||||||
|                 android:id="@+id/player_top_holder" |                 android:id="@+id/player_top_holder" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="match_parent"> |                 android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|             <TextView |             <TextView | ||||||
|                     android:layout_marginStart="80dp" |                     android:id="@+id/player_video_title" | ||||||
|                     android:layout_marginEnd="80dp" |  | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|                     app:layout_constraintTop_toTopOf="parent" |                     android:layout_marginStart="80dp" | ||||||
|                     app:layout_constraintLeft_toLeftOf="parent" |  | ||||||
|                     android:gravity="center" |  | ||||||
|                     android:layout_marginTop="35dp" |                     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_marginEnd="80dp" | ||||||
|                     android:layout_width="match_parent" |  | ||||||
|                     android:layout_height="wrap_content" |  | ||||||
|                     app:layout_constraintLeft_toLeftOf="parent" |  | ||||||
|                     android:gravity="center" |                     android:gravity="center" | ||||||
|                     android:layout_marginTop="20dp" |  | ||||||
|                     android:textColor="@color/white" |                     android:textColor="@color/white" | ||||||
|                     android:id="@+id/video_title_rez" |                     android:textStyle="bold" | ||||||
|                     tools:text="1920x1080" |  | ||||||
|                     app:layout_constraintTop_toBottomOf="@+id/video_title"> |  | ||||||
|             </TextView> |  | ||||||
|             <!-- |  | ||||||
|             <LinearLayout |  | ||||||
|                     app:layout_constraintTop_toTopOf="parent" |  | ||||||
|                     app:layout_constraintLeft_toLeftOf="parent" |                     app:layout_constraintLeft_toLeftOf="parent" | ||||||
|                     android:gravity="end" |                     app:layout_constraintTop_toTopOf="parent" | ||||||
|                     android:layout_margin="5dp" |                     tools:text="Hello world" /> | ||||||
|                     android:paddingEnd="60dp" | 
 | ||||||
|                     android:paddingStart="60dp" |             <TextView | ||||||
|  |                     android:id="@+id/player_video_title_rez" | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="wrap_content" |                     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 |             <!-- Removed as it has no use anymore--> | ||||||
|                         android:id="@+id/next_episode_btt" |             <!--<androidx.mediarouter.app.MediaRouteButton | ||||||
|                         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" |  | ||||||
|                     android:id="@+id/player_media_route_button" |                     android:id="@+id/player_media_route_button" | ||||||
|                     android:layout_width="70dp" |                     android:layout_width="70dp" | ||||||
|                     android:layout_height="70dp" |                     android:layout_height="70dp" | ||||||
|  |                     android:layout_gravity="end" | ||||||
|  |                     android:layout_margin="5dp" | ||||||
|                     android:mediaRouteTypes="user" |                     android:mediaRouteTypes="user" | ||||||
|                     android:visibility="visible" |                     android:visibility="visible" | ||||||
|                     app:layout_constraintRight_toRightOf="parent" |                     app:layout_constraintRight_toRightOf="parent" | ||||||
|                     app:layout_constraintTop_toTopOf="parent" |                     app:layout_constraintTop_toTopOf="parent" />--> | ||||||
|             /> | 
 | ||||||
|             <FrameLayout |             <FrameLayout | ||||||
|                     android:id="@+id/video_go_back_holder2" |                     android:id="@+id/player_go_back_holder" | ||||||
|                     android:layout_margin="5dp" |  | ||||||
|                     app:layout_constraintStart_toStartOf="parent" |  | ||||||
|                     app:layout_constraintTop_toTopOf="parent" |  | ||||||
|                     android:layout_width="wrap_content" |                     android:layout_width="wrap_content" | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|             > |                     android:layout_margin="5dp" | ||||||
|  |                     app:layout_constraintStart_toStartOf="parent" | ||||||
|  |                     app:layout_constraintTop_toTopOf="parent"> | ||||||
|  | 
 | ||||||
|                 <ImageView |                 <ImageView | ||||||
|                         android:layout_width="30dp" |                         android:layout_width="30dp" | ||||||
|                         android:layout_height="30dp" |                         android:layout_height="30dp" | ||||||
|                         android:layout_gravity="center" |                         android:layout_gravity="center" | ||||||
|                         android:src="@drawable/ic_baseline_arrow_back_24" |                         android:src="@drawable/ic_baseline_arrow_back_24" | ||||||
|                         app:tint="@android:color/white" |                         app:tint="@android:color/white" | ||||||
|                 > |                         android:contentDescription="@string/go_back_img_des" /> | ||||||
|                 </ImageView> | 
 | ||||||
|                 <ImageView |                 <ImageView | ||||||
|                         android:id="@+id/video_go_back" |                         android:id="@+id/player_go_back" | ||||||
|                         android:layout_width="70dp" |                         android:layout_width="70dp" | ||||||
|                         android:layout_height="70dp" |                         android:layout_height="70dp" | ||||||
|                         android:layout_gravity="center" |                         android:layout_gravity="center" | ||||||
|                         android:focusable="true" |                         android:background="@drawable/video_tap_button_always_white" | ||||||
|                         android:clickable="true" |                         android:clickable="true" | ||||||
|                         android:background="@drawable/video_tap_button_always_white"> |                         android:focusable="true" | ||||||
|                 </ImageView> |                         android:contentDescription="@string/go_back_img_des" /> | ||||||
|             </FrameLayout> |             </FrameLayout> | ||||||
|         </FrameLayout> |         </FrameLayout> | ||||||
| 
 | 
 | ||||||
| 
 |         <!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator--> | ||||||
|         <androidx.constraintlayout.widget.ConstraintLayout |         <ProgressBar | ||||||
|  |                 app:layout_constraintBottom_toBottomOf="parent" | ||||||
|                 app:layout_constraintLeft_toLeftOf="parent" |                 app:layout_constraintLeft_toLeftOf="parent" | ||||||
|                 app:layout_constraintRight_toRightOf="parent" |                 app:layout_constraintRight_toRightOf="parent" | ||||||
|                 app:layout_constraintTop_toTopOf="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_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_width="match_parent" | ||||||
|                 android:layout_height="100dp" |                 android:layout_height="100dp" | ||||||
|  |                 android:layout_gravity="center" | ||||||
|                 android:gravity="center" |                 android:gravity="center" | ||||||
|                 android:orientation="horizontal" |                 android:orientation="horizontal" | ||||||
|                 android:layout_gravity="center" |                 app:layout_constraintBottom_toBottomOf="parent" | ||||||
|                 android:id="@+id/centerMenu" |                 app:layout_constraintLeft_toLeftOf="parent" | ||||||
|         > |                 app:layout_constraintRight_toRightOf="parent" | ||||||
|  |                 app:layout_constraintTop_toTopOf="parent"> | ||||||
| 
 | 
 | ||||||
|             <FrameLayout |             <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: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_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 |                 <TextView | ||||||
|                         android:id="@+id/exo_rew_text" |                         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" |                         android:textColor="@color/white" | ||||||
|                         tools:text="10" |  | ||||||
|                         android:textSize="19sp" |                         android:textSize="19sp" | ||||||
| 
 | 
 | ||||||
|                         android:layout_gravity="center" |  | ||||||
|                         android:textStyle="bold" |                         android:textStyle="bold" | ||||||
|                         android:gravity="center" |                         tools:text="10" /> | ||||||
| 
 | 
 | ||||||
|                         android:layout_width="200dp" |  | ||||||
|                         android:layout_height="40dp"> |  | ||||||
|                 </TextView> |  | ||||||
|                 <ImageButton |                 <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:id="@id/exo_rew" | ||||||
|                         android:layout_height="70dp" |  | ||||||
|                         android:layout_width="70dp" |                         android:layout_width="70dp" | ||||||
|  |                         android:layout_height="70dp" | ||||||
|                         android:layout_gravity="center" |                         android:layout_gravity="center" | ||||||
|                         android:padding="10dp" | 
 | ||||||
|                         android:background="@drawable/video_tap_button_skip" |                         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:scaleX="-1" | ||||||
|                         android:scaleType="fitCenter" |                         android:src="@drawable/netflix_skip_forward" | ||||||
|  |                         app:tint="@color/white" | ||||||
|                         android:tintMode="src_in" |                         android:tintMode="src_in" | ||||||
|                 /> |                         tools:ignore="ContentDescription" /> | ||||||
|             </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" |  | ||||||
|                 /> |  | ||||||
|             </FrameLayout> |             </FrameLayout> | ||||||
| 
 | 
 | ||||||
|             <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: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_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 |                 <TextView | ||||||
|                         tools:text="10" |  | ||||||
|                         android:id="@+id/exo_ffwd_text" |                         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:textColor="@color/white" | ||||||
|                         android:textSize="19sp" |                         android:textSize="19sp" | ||||||
|                         android:layout_gravity="center" |  | ||||||
|                         android:textStyle="bold" |                         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:nextFocusRight="@id/exo_rew" |  | ||||||
|                         android:tint="@color/white" |  | ||||||
| 
 | 
 | ||||||
|                         android:layout_gravity="center" |                 <ImageButton | ||||||
|                         android:id="@id/exo_ffwd" |                         android:id="@id/exo_ffwd" | ||||||
|                         android:layout_height="70dp" |  | ||||||
|                         android:layout_width="70dp" |                         android:layout_width="70dp" | ||||||
|                         android:padding="10dp" |                         android:layout_height="70dp" | ||||||
|  |                         android:layout_gravity="center" | ||||||
|  | 
 | ||||||
|                         android:background="@drawable/video_tap_button_skip" |                         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:scaleType="fitCenter" | ||||||
|  |                         android:src="@drawable/netflix_skip_forward" | ||||||
|  |                         app:tint="@color/white" | ||||||
|                         android:tintMode="src_in" |                         android:tintMode="src_in" | ||||||
|                 /> |                         tools:ignore="ContentDescription" /> | ||||||
|             </FrameLayout> |             </FrameLayout> | ||||||
|         </androidx.constraintlayout.widget.ConstraintLayout> |         </androidx.constraintlayout.widget.ConstraintLayout> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         <LinearLayout |         <LinearLayout | ||||||
|                 android:layout_marginBottom="20dp" |  | ||||||
|                 android:visibility="gone" |  | ||||||
|                 android:layout_gravity="bottom" |  | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|  |                 android:layout_gravity="bottom" | ||||||
|  |                 android:layout_marginBottom="20dp" | ||||||
|                 android:gravity="center" |                 android:gravity="center" | ||||||
|                 android:orientation="horizontal" |                 android:orientation="horizontal" | ||||||
|                 android:paddingTop="4dp" |                 android:paddingTop="4dp" | ||||||
|  |                 android:visibility="gone" | ||||||
|                 app:layout_constraintBottom_toBottomOf="parent" |                 app:layout_constraintBottom_toBottomOf="parent" | ||||||
|                 app:layout_constraintEnd_toEndOf="parent" |                 app:layout_constraintEnd_toEndOf="parent"> | ||||||
|         > |  | ||||||
| 
 | 
 | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                     android:id="@id/exo_prev" |                     android:id="@id/exo_prev" | ||||||
|                     style="@style/ExoMediaButton.Previous" |                     style="@style/ExoMediaButton.Previous" | ||||||
|                     android:tint="?attr/colorPrimaryDark" |                     app:tint="?attr/colorPrimaryDark" | ||||||
|                     android:tintMode="src_in"/> |                     android:tintMode="src_in" | ||||||
|  |                     tools:ignore="ContentDescription" /> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                     android:id="@id/exo_repeat_toggle" |                     android:id="@id/exo_repeat_toggle" | ||||||
|                     style="@style/ExoMediaButton" |                     style="@style/ExoMediaButton" | ||||||
|                     android:tint="?attr/colorPrimaryDark" |                     app:tint="?attr/colorPrimaryDark" | ||||||
|                     android:tintMode="src_in"/> |                     android:tintMode="src_in" | ||||||
|  |                     tools:ignore="ContentDescription" /> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                     android:id="@id/exo_next" |                     android:id="@id/exo_next" | ||||||
|                     style="@style/ExoMediaButton.Next" |                     style="@style/ExoMediaButton.Next" | ||||||
|                     android:tint="?attr/colorPrimaryDark" |                     app:tint="?attr/colorPrimaryDark" | ||||||
|                     android:tintMode="src_in"/> |                     android:tintMode="src_in" | ||||||
|  |                     tools:ignore="ContentDescription" /> | ||||||
| 
 | 
 | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                     android:id="@id/exo_vr" |                     android:id="@id/exo_vr" | ||||||
|                     style="@style/ExoMediaButton.VR" |                     style="@style/ExoMediaButton.VR" | ||||||
|                     android:tint="?attr/colorPrimaryDark" |                     app:tint="?attr/colorPrimaryDark" | ||||||
|                     android:tintMode="src_in"/> |                     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> | ||||||
| 
 | 
 | ||||||
|         <LinearLayout |         <LinearLayout | ||||||
|  |                 android:id="@+id/bottom_player_bar" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:layout_marginBottom="10dp" |                 android:layout_marginBottom="10dp" | ||||||
|                 android:gravity="center_vertical" |                 android:gravity="center_vertical" | ||||||
|                 android:orientation="vertical" |                 android:orientation="vertical" | ||||||
|                 app:layout_constraintBottom_toBottomOf="parent" |                 app:layout_constraintBottom_toBottomOf="parent" | ||||||
|                 app:layout_constraintEnd_toEndOf="parent" |                 app:layout_constraintEnd_toEndOf="parent"> | ||||||
|                 android:id="@+id/bottom_player_bar"> |  | ||||||
| 
 | 
 | ||||||
|             <LinearLayout |             <LinearLayout | ||||||
|  |                     android:id="@+id/player_video_bar" | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|                     android:orientation="horizontal" |                     android:orientation="horizontal"> | ||||||
|                     android:id="@+id/video_bar" | 
 | ||||||
|             > |  | ||||||
|                 <TextView |                 <TextView | ||||||
|                         tools:text="15:30" |  | ||||||
|                         android:layout_marginStart="20dp" |  | ||||||
|                         android:id="@id/exo_position" |                         android:id="@id/exo_position" | ||||||
|                         android:layout_gravity="center" |  | ||||||
|                         android:layout_width="wrap_content" |                         android:layout_width="wrap_content" | ||||||
|                         android:layout_height="wrap_content" |                         android:layout_height="wrap_content" | ||||||
|  |                         android:layout_gravity="center" | ||||||
|  |                         android:layout_marginStart="20dp" | ||||||
|  |                         android:gravity="end" | ||||||
|                         android:includeFontPadding="false" |                         android:includeFontPadding="false" | ||||||
|  |                         android:minWidth="50dp" | ||||||
|                         android:paddingLeft="4dp" |                         android:paddingLeft="4dp" | ||||||
|                         android:paddingRight="4dp" |                         android:paddingRight="4dp" | ||||||
|                         android:gravity="end" |  | ||||||
|                         android:minWidth="50dp" |  | ||||||
|                         android:textColor="@android:color/white" |                         android:textColor="@android:color/white" | ||||||
|                         android:textSize="14sp" |                         android:textSize="14sp" | ||||||
|                         android:textStyle="normal"/> |                         android:textStyle="normal" | ||||||
|  |                         tools:text="15:30" /> | ||||||
|                 <!--app:buffered_color="@color/videoCache"--> |                 <!--app:buffered_color="@color/videoCache"--> | ||||||
|                 <com.google.android.exoplayer2.ui.DefaultTimeBar |                 <com.google.android.exoplayer2.ui.DefaultTimeBar | ||||||
|                         android:id="@id/exo_progress" |                         android:id="@id/exo_progress" | ||||||
|                         android:layout_width="0dp" |                         android:layout_width="0dp" | ||||||
|                         android:layout_height="30dp" |                         android:layout_height="30dp" | ||||||
|                         android:layout_weight="1" |                         android:layout_weight="1" | ||||||
|                         app:scrubber_enabled_size="24dp" |  | ||||||
|                         app:scrubber_dragged_size="26dp" |  | ||||||
| 
 |  | ||||||
|                         app:scrubber_color="?attr/colorPrimary" |  | ||||||
|                         app:bar_height="2dp" |                         app:bar_height="2dp" | ||||||
|                         app:played_color="?attr/colorPrimary" |                         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--> |                 <!-- exo_duration--> | ||||||
|                 <TextView |                 <TextView | ||||||
|                         tools:text="23:20" |  | ||||||
|                         android:id="@id/exo_duration" |                         android:id="@id/exo_duration" | ||||||
|                         android:layout_width="wrap_content" |                         android:layout_width="wrap_content" | ||||||
|                         android:layout_height="wrap_content" |                         android:layout_height="wrap_content" | ||||||
|  |                         android:layout_gravity="center" | ||||||
|  |                         android:layout_marginEnd="20dp" | ||||||
|                         android:includeFontPadding="false" |                         android:includeFontPadding="false" | ||||||
|  |                         android:minWidth="50dp" | ||||||
|                         android:paddingLeft="4dp" |                         android:paddingLeft="4dp" | ||||||
|                         android:paddingRight="4dp" |                         android:paddingRight="4dp" | ||||||
|                         android:minWidth="50dp" |  | ||||||
|                         android:textColor="@android:color/white" |                         android:textColor="@android:color/white" | ||||||
|                         android:textSize="14sp" |                         android:textSize="14sp" | ||||||
|                         android:textStyle="normal" |                         android:textStyle="normal" | ||||||
|                         android:layout_marginEnd="20dp" |                         tools:text="23:20" /> | ||||||
|                         android:layout_gravity="center" |  | ||||||
|                 /> |  | ||||||
| 
 | 
 | ||||||
|             </LinearLayout> |             </LinearLayout> | ||||||
|  | 
 | ||||||
|             <HorizontalScrollView |             <HorizontalScrollView | ||||||
|                     android:layout_gravity="center" |  | ||||||
|                     android:layout_width="wrap_content" |                     android:layout_width="wrap_content" | ||||||
|                     android:layout_height="wrap_content"> |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_gravity="center"> | ||||||
|  | 
 | ||||||
|                 <LinearLayout |                 <LinearLayout | ||||||
|                         android:layout_width="match_parent" |                         android:layout_width="wrap_content" | ||||||
|                         android:layout_height="60dp" |                         android:layout_height="60dp" | ||||||
|                         android:orientation="horizontal" |  | ||||||
|                         android:gravity="center" |                         android:gravity="center" | ||||||
|  |                         android:orientation="horizontal" | ||||||
|                         android:paddingTop="10dp" |                         android:paddingTop="10dp" | ||||||
|                         android:paddingBottom="10dp" |                         android:paddingBottom="10dp"> | ||||||
|                 > | 
 | ||||||
|                     <com.google.android.material.button.MaterialButton |                     <com.google.android.material.button.MaterialButton | ||||||
|                             android:nextFocusLeft="@id/skip_episode" |                             android:id="@+id/player_lock" | ||||||
|                             android:nextFocusRight="@id/resize_player" |                             style="@style/VideoButton" | ||||||
|                             android:id="@+id/lock_player" |                             android:nextFocusLeft="@id/player_skip_episode" | ||||||
|                             app:iconSize="30dp" |                             android:nextFocusRight="@id/player_resize_btt" | ||||||
|                             android:text="@string/video_lock" |                             android:text="@string/video_lock" | ||||||
|                             app:icon="@drawable/video_locked" |                             app:icon="@drawable/video_locked" | ||||||
| 
 | 
 | ||||||
|                             style="@style/VideoButton"/> |                             app:iconSize="30dp" /> | ||||||
|  | 
 | ||||||
|                     <LinearLayout |                     <LinearLayout | ||||||
|                             android:id="@+id/lock_holder" |                             android:id="@+id/player_lock_holder" | ||||||
|                             android:orientation="horizontal" |  | ||||||
|                             android:layout_width="wrap_content" |                             android:layout_width="wrap_content" | ||||||
|                             android:layout_height="match_parent"> |                             android:layout_height="match_parent" | ||||||
|  |                             android:orientation="horizontal"> | ||||||
| 
 | 
 | ||||||
|                         <com.google.android.material.button.MaterialButton |                         <com.google.android.material.button.MaterialButton | ||||||
|                                 android:nextFocusLeft="@id/lock_player" |                                 android:id="@+id/player_resize_btt" | ||||||
|                                 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" |  | ||||||
|                                 style="@style/VideoButton" |                                 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> | ||||||
|                 </LinearLayout> |                 </LinearLayout> | ||||||
|             </HorizontalScrollView> |             </HorizontalScrollView> | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|     </androidx.constraintlayout.widget.ConstraintLayout> |     </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 |     <LinearLayout | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="match_parent" |             android:layout_height="match_parent" | ||||||
|             android:orientation="horizontal"> |             android:orientation="horizontal"> | ||||||
|  | 
 | ||||||
|         <RelativeLayout |         <RelativeLayout | ||||||
|  |                 android:id="@+id/player_progressbar_left_holder" | ||||||
|  |                 android:layout_width="100dp" | ||||||
|  |                 android:layout_height="wrap_content" | ||||||
|                 android:layout_gravity="center_vertical" |                 android:layout_gravity="center_vertical" | ||||||
|                 android:gravity="left" |                 android:gravity="start" | ||||||
|                 tools:alpha="1" |                 android:visibility="gone" | ||||||
|                 app:layout_constraintTop_toTopOf="parent" |  | ||||||
|                 app:layout_constraintBottom_toBottomOf="parent" |                 app:layout_constraintBottom_toBottomOf="parent" | ||||||
|                 app:layout_constraintLeft_toLeftOf="parent" |                 app:layout_constraintLeft_toLeftOf="parent" | ||||||
|                 app:layout_constraintRight_toLeftOf="@+id/centerMenuView" |                 app:layout_constraintRight_toLeftOf="@+id/centerMenuView" | ||||||
|                 android:id="@+id/progressBarLeftHolder" |                 app:layout_constraintTop_toTopOf="parent" | ||||||
|                 android:layout_width="100dp" |                 tools:alpha="1" | ||||||
|                 android:layout_height="wrap_content" |                 tools:visibility="visible"> | ||||||
|                 android:alpha="0" |  | ||||||
|         > |  | ||||||
|             <!--VERY hacky layout --> |             <!--VERY hacky layout --> | ||||||
|             <ImageView |             <ImageView | ||||||
|                     android:layout_marginBottom="220dp" |                     android:id="@+id/player_progressbar_left_icon" | ||||||
|                     android:layout_centerHorizontal="true" |  | ||||||
|                     android:layout_width="wrap_content" |                     android:layout_width="wrap_content" | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_centerHorizontal="true" | ||||||
|  |                     android:layout_marginBottom="220dp" | ||||||
|                     android:src="@drawable/ic_baseline_volume_up_24" |                     android:src="@drawable/ic_baseline_volume_up_24" | ||||||
|                     app:tint="@android:color/white" |                     app:tint="@android:color/white" | ||||||
|             > |                     tools:ignore="ContentDescription"> | ||||||
| 
 | 
 | ||||||
|             </ImageView> |             </ImageView> | ||||||
| 
 | 
 | ||||||
|             <ProgressBar |             <ProgressBar | ||||||
|                     android:layout_centerVertical="true" |                     android:id="@+id/player_progressbar_left" | ||||||
|                     android:layout_centerHorizontal="true" |                     style="@android:style/Widget.Material.ProgressBar.Horizontal" | ||||||
|                     android:layout_width="4dp" |                     android:layout_width="4dp" | ||||||
|                     android:layout_height="150dp" |                     android:layout_height="150dp" | ||||||
|                     android:id="@+id/progressBarLeft" |                     android:layout_centerHorizontal="true" | ||||||
|                     android:indeterminate="false" |                     android:layout_centerVertical="true" | ||||||
|                     style="@android:style/Widget.Material.ProgressBar.Horizontal" |  | ||||||
|                     android:max="100" |  | ||||||
|                     android:layout_marginStart="40dp" |  | ||||||
|                     android:layout_gravity="end|center_vertical" |                     android:layout_gravity="end|center_vertical" | ||||||
|  |                     android:layout_marginStart="40dp" | ||||||
|  |                     android:indeterminate="false" | ||||||
|  |                     android:max="100" | ||||||
|                     android:progress="100" |                     android:progress="100" | ||||||
|                     android:progressDrawable="@drawable/progress_drawable_vertical" |                     android:progressDrawable="@drawable/progress_drawable_vertical" | ||||||
|             /> |                     tools:progress="30" /> | ||||||
|         </RelativeLayout> |         </RelativeLayout> | ||||||
|  | 
 | ||||||
|         <RelativeLayout |         <RelativeLayout | ||||||
|                 android:layout_gravity="center_vertical" |                 android:id="@+id/player_progressbar_right_holder" | ||||||
|                 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:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:alpha="0" |                 android:layout_gravity="center_vertical" | ||||||
|                 tools:ignore="RtlHardcoded"> |                 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 |             <ImageView | ||||||
|                     android:layout_marginBottom="220dp" |                     android:id="@+id/player_progressbar_right_icon" | ||||||
|                     android:layout_centerHorizontal="true" |  | ||||||
|                     android:layout_width="wrap_content" |                     android:layout_width="wrap_content" | ||||||
|                     android:layout_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_centerHorizontal="true" | ||||||
|  |                     android:layout_marginBottom="220dp" | ||||||
|                     android:src="@drawable/ic_baseline_brightness_7_24" |                     android:src="@drawable/ic_baseline_brightness_7_24" | ||||||
|                     app:tint="@android:color/white" |                     app:tint="@android:color/white" | ||||||
|             > |                     tools:ignore="ContentDescription"> | ||||||
| 
 | 
 | ||||||
|             </ImageView> |             </ImageView> | ||||||
| 
 | 
 | ||||||
|             <ProgressBar |             <ProgressBar | ||||||
|                     android:layout_centerVertical="true" |                     android:id="@+id/player_progressbar_right" | ||||||
|                     android:layout_centerHorizontal="true" |                     style="@android:style/Widget.Material.ProgressBar.Horizontal" | ||||||
|                     android:layout_width="4dp" |                     android:layout_width="4dp" | ||||||
|                     android:layout_height="150dp" |                     android:layout_height="150dp" | ||||||
|                     android:id="@+id/progressBarRight" |                     android:layout_centerHorizontal="true" | ||||||
|                     android:indeterminate="false" |                     android:layout_centerVertical="true" | ||||||
|                     style="@android:style/Widget.Material.ProgressBar.Horizontal" |  | ||||||
|                     android:max="100" |  | ||||||
|                     android:layout_marginEnd="40dp" |  | ||||||
|                     android:layout_gravity="end|center_vertical" |                     android:layout_gravity="end|center_vertical" | ||||||
|  |                     android:layout_marginEnd="40dp" | ||||||
|  |                     android:indeterminate="false" | ||||||
|  |                     android:max="100" | ||||||
|                     android:progress="100" |                     android:progress="100" | ||||||
|                     android:progressDrawable="@drawable/progress_drawable_vertical" |                     android:progressDrawable="@drawable/progress_drawable_vertical" /> | ||||||
|             > |  | ||||||
|             </ProgressBar> |  | ||||||
|         </RelativeLayout> |         </RelativeLayout> | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| </FrameLayout> | </FrameLayout> | ||||||
|  |  | ||||||
|  | @ -1,150 +1,129 @@ | ||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|     xmlns:tools="http://schemas.android.com/tools" |         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 |  | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="match_parent" |         android:layout_height="match_parent" | ||||||
|         android:layout_marginBottom="60dp" |         android:background="@null" | ||||||
|         android:baselineAligned="false" |         android:orientation="vertical"> | ||||||
|         android:orientation="horizontal"> | 
 | ||||||
|  |     <LinearLayout | ||||||
|  |             android:layout_width="match_parent" | ||||||
|  |             android:layout_height="match_parent" | ||||||
|  |             android:layout_marginBottom="60dp" | ||||||
|  |             android:baselineAligned="false" | ||||||
|  |             android:orientation="horizontal"> | ||||||
| 
 | 
 | ||||||
|         <LinearLayout |         <LinearLayout | ||||||
|             android:id="@+id/sort_sources_holder" |                 android:id="@+id/sort_sources_holder" | ||||||
|             android:layout_width="0dp" |                 android:layout_width="0dp" | ||||||
|             android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|             android:layout_weight="50" |                 android:layout_weight="50" | ||||||
|             android:orientation="vertical"> |                 android:orientation="vertical"> | ||||||
| 
 | 
 | ||||||
|             <TextView |             <TextView | ||||||
|                 android:layout_width="match_parent" |                     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_height="wrap_content" |                     android:layout_height="wrap_content" | ||||||
|                     android:layout_rowWeight="1" |                     android:layout_rowWeight="1" | ||||||
| 
 |                     android:layout_marginTop="10dp" | ||||||
|                     android:layout_weight="1" |  | ||||||
|                     android:nextFocusRight="@id/sort_providers" |  | ||||||
| 
 |  | ||||||
|                     android:nextFocusDown="@id/sort_subtitles" |  | ||||||
|                     android:paddingStart="?android:attr/listPreferredItemPaddingStart" |                     android:paddingStart="?android:attr/listPreferredItemPaddingStart" | ||||||
|  |                     android:paddingTop="10dp" | ||||||
|                     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" |                     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" | ||||||
|                     android:text="@string/pick_subtitle" |                     android:paddingBottom="10dp" | ||||||
|  |                     android:text="@string/pick_source" | ||||||
|                     android:textColor="?attr/textColor" |                     android:textColor="?attr/textColor" | ||||||
|                     android:textSize="20sp" |                     android:textSize="20sp" | ||||||
|                     android:textStyle="bold" /> |                     android:textStyle="bold" /> | ||||||
| 
 | 
 | ||||||
|                 <ImageView |             <ListView | ||||||
|                     android:layout_width="25dp" |                     android:requiresFadingEdge="vertical" | ||||||
|                     android:layout_height="wrap_content" |                     android:id="@+id/sort_providers" | ||||||
|                     android:layout_gravity="end|center_vertical" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_marginTop="0dp" |  | ||||||
|                     android:layout_marginEnd="10dp" |  | ||||||
| 
 | 
 | ||||||
|                     android:contentDescription="@string/home_change_provider_img_des" |                     android:layout_height="match_parent" | ||||||
|                     android:src="@drawable/ic_outline_settings_24" |                     android:layout_rowWeight="1" | ||||||
|                     android:visibility="gone" /> |                     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> |             </LinearLayout> | ||||||
| 
 | 
 | ||||||
|             <ListView |             <ListView | ||||||
|                 android:id="@+id/sort_subtitles" |                     android:requiresFadingEdge="vertical" | ||||||
|                 android:layout_width="match_parent" |                     android:id="@+id/sort_subtitles" | ||||||
|  |                     android:layout_width="match_parent" | ||||||
| 
 | 
 | ||||||
|                 android:layout_height="match_parent" |                     android:layout_height="match_parent" | ||||||
|                 android:layout_rowWeight="1" |                     android:layout_rowWeight="1" | ||||||
|                 android:background="?attr/primaryBlackBackground" |                     android:background="?attr/primaryBlackBackground" | ||||||
|                 android:nextFocusLeft="@id/sort_providers" |                     android:nextFocusLeft="@id/sort_providers" | ||||||
|                 android:nextFocusRight="@id/cancel_btt" |                     android:nextFocusRight="@id/cancel_btt" | ||||||
|                 tools:listitem="@layout/sort_bottom_single_choice" /> |                     tools:listfooter="@layout/sort_bottom_footer_add_choice" | ||||||
|  |                     tools:listitem="@layout/sort_bottom_single_choice" /> | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| 
 | 
 | ||||||
|     <LinearLayout |     <LinearLayout | ||||||
|         android:layout_width="match_parent" |             android:id="@+id/apply_btt_holder" | ||||||
|         android:layout_height="60dp" |             android:orientation="horizontal" | ||||||
|         android:layout_gravity="bottom" |             android:layout_gravity="bottom" | ||||||
|         android:layout_marginTop="-60dp" |             android:gravity="bottom|end" | ||||||
|         android:orientation="horizontal"> |             android:layout_marginTop="-60dp" | ||||||
|  |             android:layout_width="match_parent" | ||||||
|  |             android:layout_height="60dp"> | ||||||
| 
 | 
 | ||||||
| <!--        Kinda hack because the gravity won't behave correctly--> |         <com.google.android.material.button.MaterialButton | ||||||
|         <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" |  | ||||||
|                 style="@style/WhiteButton" |                 style="@style/WhiteButton" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_gravity="center_vertical|end" | ||||||
|                 android:nextFocusLeft="@id/cancel_btt" |                 android:text="@string/sort_apply" | ||||||
|                 android:nextFocusRight="@id/apply_btt" |                 android:id="@+id/apply_btt" | ||||||
|                 android:text="@string/player_load_subtitles" /> |                 android:layout_width="wrap_content" /> | ||||||
|         </LinearLayout> |  | ||||||
| 
 | 
 | ||||||
|         <com.google.android.material.button.MaterialButton |         <com.google.android.material.button.MaterialButton | ||||||
|             android:id="@+id/apply_btt" |                 style="@style/BlackButton" | ||||||
|             style="@style/WhiteButton" |                 android:layout_gravity="center_vertical|end" | ||||||
|             android:layout_width="wrap_content" |                 android:text="@string/sort_cancel" | ||||||
|             android:layout_gravity="center_vertical|end" |                 android:id="@+id/cancel_btt" | ||||||
|             android:nextFocusLeft="@id/cancel_btt" |                 android:layout_width="wrap_content" /> | ||||||
|             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" /> |  | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| </LinearLayout> | </LinearLayout> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <androidx.cardview.widget.CardView | <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|         xmlns:android="http://schemas.android.com/apk/res/android" |  | ||||||
|         xmlns:app="http://schemas.android.com/apk/res-auto" |         xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|         xmlns:tools="http://schemas.android.com/tools" |         xmlns:tools="http://schemas.android.com/tools" | ||||||
| 
 | 
 | ||||||
|  | @ -15,8 +14,7 @@ | ||||||
|         app:cardBackgroundColor="@color/transparent" |         app:cardBackgroundColor="@color/transparent" | ||||||
|         app:cardElevation="0dp" |         app:cardElevation="0dp" | ||||||
|         android:foreground="@drawable/outline_drawable" |         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 --> |     <!-- IDK BUT THIS DOES NOT SEAM LIKE A GOOD WAY OF DOING IT --> | ||||||
|     <!--<LinearLayout |     <!--<LinearLayout | ||||||
|             android:layout_width="fill_parent" |             android:layout_width="fill_parent" | ||||||
|  | @ -48,14 +46,15 @@ | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             tools:progress="50" |             tools:progress="50" | ||||||
|             android:layout_gravity="bottom" |             android:layout_gravity="bottom" | ||||||
|             android:layout_height="5dp"> |             android:layout_height="5dp" /> | ||||||
|     </androidx.core.widget.ContentLoadingProgressBar> | 
 | ||||||
|     <LinearLayout |     <LinearLayout | ||||||
|             android:foreground="?android:attr/selectableItemBackgroundBorderless" |             android:foreground="?android:attr/selectableItemBackgroundBorderless" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="match_parent"> |             android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|         <ImageView |         <ImageView | ||||||
|                 android:tint="?attr/textColor" |                 app:tint="?attr/textColor" | ||||||
|                 android:layout_marginStart="10dp" |                 android:layout_marginStart="10dp" | ||||||
|                 android:layout_marginEnd="10dp" |                 android:layout_marginEnd="10dp" | ||||||
|                 android:layout_gravity="center_vertical" |                 android:layout_gravity="center_vertical" | ||||||
|  | @ -63,15 +62,21 @@ | ||||||
|                 android:src="@drawable/ic_baseline_play_arrow_24" |                 android:src="@drawable/ic_baseline_play_arrow_24" | ||||||
|                 android:contentDescription="@string/episode_play_img_des" |                 android:contentDescription="@string/episode_play_img_des" | ||||||
|                 android:layout_height="match_parent" |                 android:layout_height="match_parent" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_width="wrap_content" /> | ||||||
|         /> |  | ||||||
|         <!--marquee_forever--> |         <!--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 |         <TextView | ||||||
|                 android:id="@+id/episode_text" |                 android:id="@+id/episode_text" | ||||||
|                 android:layout_marginStart="10dp" |                 android:layout_marginStart="10dp" | ||||||
|                 android:layout_marginEnd="50dp" |                 android:layout_marginEnd="50dp" | ||||||
|                 android:layout_gravity="center_vertical" |                 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:textColor="?attr/textColor" | ||||||
| 
 | 
 | ||||||
|                 android:scrollHorizontally="true" |                 android:scrollHorizontally="true" | ||||||
|  | @ -81,14 +86,14 @@ | ||||||
|                 android:singleLine="true" |                 android:singleLine="true" | ||||||
| 
 | 
 | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="match_parent"> |                 android:layout_height="match_parent" /> | ||||||
|         </TextView> |  | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| 
 | 
 | ||||||
|     <FrameLayout |     <FrameLayout | ||||||
|             android:layout_gravity="end" |             android:layout_gravity="end" | ||||||
|             android:layout_width="wrap_content" |             android:layout_width="wrap_content" | ||||||
|             android:layout_height="match_parent"> |             android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|         <androidx.core.widget.ContentLoadingProgressBar |         <androidx.core.widget.ContentLoadingProgressBar | ||||||
|                 android:layout_marginEnd="10dp" |                 android:layout_marginEnd="10dp" | ||||||
|                 android:layout_marginStart="10dp" |                 android:layout_marginStart="10dp" | ||||||
|  | @ -103,13 +108,13 @@ | ||||||
|                 android:layout_margin="5dp" |                 android:layout_margin="5dp" | ||||||
|                 android:layout_gravity="end|center_vertical" |                 android:layout_gravity="end|center_vertical" | ||||||
|                 android:progress="0" |                 android:progress="0" | ||||||
|                 android:visibility="visible" |                 android:visibility="visible" /> | ||||||
|         /> | 
 | ||||||
|         <ImageView |         <ImageView | ||||||
|                 android:nextFocusLeft="@id/episode_holder" |                 android:nextFocusLeft="@id/episode_holder" | ||||||
|                 android:nextFocusRight="@id/episode_holder" |                 android:nextFocusRight="@id/episode_holder" | ||||||
| 
 | 
 | ||||||
|                 android:tint="?attr/white" |                 app:tint="?attr/white" | ||||||
| 
 | 
 | ||||||
|                 android:id="@+id/result_episode_download" |                 android:id="@+id/result_episode_download" | ||||||
|                 android:visibility="visible" |                 android:visibility="visible" | ||||||
|  | @ -121,6 +126,6 @@ | ||||||
|                 android:layout_width="30dp" |                 android:layout_width="30dp" | ||||||
|                 android:background="?selectableItemBackgroundBorderless" |                 android:background="?selectableItemBackgroundBorderless" | ||||||
|                 android:src="@drawable/ic_baseline_play_arrow_24" |                 android:src="@drawable/ic_baseline_play_arrow_24" | ||||||
|                 android:contentDescription="@string/download"/> |                 android:contentDescription="@string/download" /> | ||||||
|     </FrameLayout> |     </FrameLayout> | ||||||
| </androidx.cardview.widget.CardView> | </androidx.cardview.widget.CardView> | ||||||
|  | @ -71,14 +71,28 @@ | ||||||
|                     android:layout_width="match_parent" |                     android:layout_width="match_parent" | ||||||
|                     android:layout_marginEnd="50dp" |                     android:layout_marginEnd="50dp" | ||||||
|                     android:layout_height="wrap_content"> |                     android:layout_height="wrap_content"> | ||||||
|                 <TextView | 
 | ||||||
|                         android:id="@+id/episode_text" |                 <LinearLayout | ||||||
|                         tools:text="1. Jobless" |                         android:orientation="horizontal" | ||||||
|                         android:textStyle="bold" |  | ||||||
|                         android:textColor="?attr/textColor" |  | ||||||
|                         android:layout_width="wrap_content" |                         android:layout_width="wrap_content" | ||||||
|                         android:layout_height="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 |                 <TextView | ||||||
|                         android:id="@+id/episode_rating" |                         android:id="@+id/episode_rating" | ||||||
|                         tools:text="Rated: 8.8" |                         tools:text="Rated: 8.8" | ||||||
|  | @ -113,8 +127,6 @@ | ||||||
|                         android:nextFocusRight="@id/episode_holder" |                         android:nextFocusRight="@id/episode_holder" | ||||||
|                         android:id="@+id/result_episode_download" |                         android:id="@+id/result_episode_download" | ||||||
| 
 | 
 | ||||||
|                         android:tint="?attr/white" |  | ||||||
| 
 |  | ||||||
|                         android:visibility="visible" |                         android:visibility="visible" | ||||||
|                         android:layout_marginEnd="10dp" |                         android:layout_marginEnd="10dp" | ||||||
|                         android:layout_marginStart="10dp" |                         android:layout_marginStart="10dp" | ||||||
|  | @ -124,7 +136,8 @@ | ||||||
|                         android:layout_width="30dp" |                         android:layout_width="30dp" | ||||||
|                         android:background="?selectableItemBackgroundBorderless" |                         android:background="?selectableItemBackgroundBorderless" | ||||||
|                         android:src="@drawable/ic_baseline_play_arrow_24" |                         android:src="@drawable/ic_baseline_play_arrow_24" | ||||||
|                         android:contentDescription="@string/download"/> |                         android:contentDescription="@string/download" | ||||||
|  |                         app:tint="?attr/white" /> | ||||||
|             </FrameLayout> |             </FrameLayout> | ||||||
|         </LinearLayout> |         </LinearLayout> | ||||||
|         <TextView |         <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 | <TextView | ||||||
|         xmlns:android="http://schemas.android.com/apk/res/android" |         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" |         xmlns:tools="http://schemas.android.com/tools" | ||||||
|         style="@style/AppTextViewStyle" |         style="@style/AppTextViewStyle" | ||||||
|         android:id="@android:id/text1" |         android:id="@android:id/text1" | ||||||
|  | @ -32,8 +33,7 @@ | ||||||
|         android:checkMark="?android:attr/listChoiceIndicatorSingle" |         android:checkMark="?android:attr/listChoiceIndicatorSingle" | ||||||
|         android:ellipsize="marquee" |         android:ellipsize="marquee" | ||||||
|         android:foreground="?attr/selectableItemBackgroundBorderless" |         android:foreground="?attr/selectableItemBackgroundBorderless" | ||||||
|         android:drawableStart="@drawable/ic_baseline_check_24" |  | ||||||
|         android:drawableTint="@color/check_selection_color" |  | ||||||
|         tools:drawableTint="?attr/textColor" |         tools:drawableTint="?attr/textColor" | ||||||
|         android:drawablePadding="20dp" |         android:drawablePadding="20dp" | ||||||
| /> |         app:drawableTint="@color/check_selection_color" | ||||||
|  |         app:drawableStartCompat="@drawable/ic_baseline_check_24" /> | ||||||
|  |  | ||||||
|  | @ -188,5 +188,5 @@ | ||||||
|     <fragment |     <fragment | ||||||
|             android:id="@+id/navigation_player" |             android:id="@+id/navigation_player" | ||||||
|             android:layout_height="match_parent" |             android:layout_height="match_parent" | ||||||
|             android:name="com.lagradost.cloudstream3.ui.player.PlayerFragment"/> |             android:name="com.lagradost.cloudstream3.ui.player.GeneratorPlayer"/> | ||||||
| </navigation> | </navigation> | ||||||
|  | @ -13,7 +13,6 @@ | ||||||
|     <string name="player_speed_text_format" formatted="true">سرعة (%.2fx)</string> |     <string name="player_speed_text_format" formatted="true">سرعة (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Rated: %.1f</string> |     <string name="rated_format" formatted="true">Rated: %.1f</string> | ||||||
|     <string name="new_update_format" formatted="true">!تم إيجاد تحديث جديد\n%s -> %s</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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">الصفحة الرئيسية</string> |     <string name="title_home">الصفحة الرئيسية</string> | ||||||
|  | @ -43,7 +42,7 @@ | ||||||
|     <string name="pick_source">المصادر</string> |     <string name="pick_source">المصادر</string> | ||||||
|     <string name="pick_subtitle">الترجمة</string> |     <string name="pick_subtitle">الترجمة</string> | ||||||
|     <string name="reload_error">…إعادة محاولة الاتصال</string> |     <string name="reload_error">…إعادة محاولة الاتصال</string> | ||||||
|     <string name="result_go_back">ارجع للخلف</string> |     <string name="go_back">ارجع للخلف</string> | ||||||
|     <string name="play_episode">تشغيل الحلقة</string> |     <string name="play_episode">تشغيل الحلقة</string> | ||||||
|     <!--<string name="need_storage">السماح بتحميل الحلقات</string>--> |     <!--<string name="need_storage">السماح بتحميل الحلقات</string>--> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ | ||||||
|     <string name="player_speed_text_format" formatted="true">Geschwindigkeit (%.2fx)</string> |     <string name="player_speed_text_format" formatted="true">Geschwindigkeit (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Bewertung: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Startseite</string> |     <string name="title_home">Startseite</string> | ||||||
|     <string name="title_search">Suchen</string> |     <string name="title_search">Suchen</string> | ||||||
|  | @ -37,7 +36,7 @@ | ||||||
|     <string name="pick_source">Quellen</string> |     <string name="pick_source">Quellen</string> | ||||||
|     <string name="pick_subtitle">Untertitel</string> |     <string name="pick_subtitle">Untertitel</string> | ||||||
|     <string name="reload_error">Verbindung wiederholen…</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="play_episode">Episode abspielen</string> | ||||||
|     <string name="download">Herunterladen</string> |     <string name="download">Herunterladen</string> | ||||||
|     <string name="downloaded">Heruntergeladen</string> |     <string name="downloaded">Heruntergeladen</string> | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
|      <string name="player_speed_text_format" formatted="true">Velocidad (%.2fx)</string> |      <string name="player_speed_text_format" formatted="true">Velocidad (%.2fx)</string> | ||||||
|      <string name="rated_format" formatted="true">Puntuado: %.1f</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="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="app_name">CloudStream</string> | ||||||
|      <string name="title_home">Inicio</string> |      <string name="title_home">Inicio</string> | ||||||
|      <string name="title_search">Buscar</string> |      <string name="title_search">Buscar</string> | ||||||
|  | @ -38,7 +38,7 @@ | ||||||
|      <string name="pick_source">Fuentes</string> |      <string name="pick_source">Fuentes</string> | ||||||
|      <string name="pick_subtitle">Subtítulos</string> |      <string name="pick_subtitle">Subtítulos</string> | ||||||
|      <string name="reload_error">Reintentar conexión…</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="play_episode">Reproducir capítulo</string> | ||||||
|      <string name="download">Descarga</string> |      <string name="download">Descarga</string> | ||||||
|      <string name="downloaded">Descargada</string> |      <string name="downloaded">Descargada</string> | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ | ||||||
|     <string name="pick_source">Sources</string> |     <string name="pick_source">Sources</string> | ||||||
|     <string name="pick_subtitle">Sous-titres</string> |     <string name="pick_subtitle">Sous-titres</string> | ||||||
|     <string name="reload_error">Réessayer la connection…</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="episode_poster_img_des">Miniature de l\'Episode</string> | ||||||
|     <string name="play_episode">Lire l\'Episode</string> |     <string name="play_episode">Lire l\'Episode</string> | ||||||
|     <string name="need_storage">Permet de télécharger les épisodes</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="dns_pref_summary">Utile pour contourner les bloquages des FAI</string> | ||||||
|     <string name="new_update_format" formatted="true">Nouvelle mise à jour trouvée ! |     <string name="new_update_format" formatted="true">Nouvelle mise à jour trouvée ! | ||||||
| \n%s -> %s</string> | \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="watch_quality_pref">Qualité de visionnage préférée</string> | ||||||
|     <string name="resize_fill">Étendre</string> |     <string name="resize_fill">Étendre</string> | ||||||
|     <string name="legal_notice">Non-responsabilité</string> |     <string name="legal_notice">Non-responsabilité</string> | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ | ||||||
|     <string name="pick_source">Πηγές</string> |     <string name="pick_source">Πηγές</string> | ||||||
|     <string name="pick_subtitle">Υπότιτλοι</string> |     <string name="pick_subtitle">Υπότιτλοι</string> | ||||||
|     <string name="reload_error">Ξανά φόρτωσε…</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="episode_poster_img_des">Πόστερ</string> | ||||||
|     <string name="play_episode">Αναπαραγωγή Επισοδείου</string> |     <string name="play_episode">Αναπαραγωγή Επισοδείου</string> | ||||||
|     <string name="need_storage">Δώσε άδεια για την λήψη επισοδείου</string> |     <string name="need_storage">Δώσε άδεια για την λήψη επισοδείου</string> | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ | ||||||
|     <string name="play_torrent_button">टोरेंट चलाये</string> |     <string name="play_torrent_button">टोरेंट चलाये</string> | ||||||
|     <string name="pick_source">सूत्र</string> |     <string name="pick_source">सूत्र</string> | ||||||
|     <string name="reload_error">फिरसे प्रयास करे…</string> |     <string name="reload_error">फिरसे प्रयास करे…</string> | ||||||
|     <string name="result_go_back">वापिस जाए</string> |     <string name="go_back">वापिस जाए</string> | ||||||
|     <string name="play_episode">एपिसोड चलाये</string> |     <string name="play_episode">एपिसोड चलाये</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</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="player_speed_text_format" formatted="true">Брзина (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Оценето: %.1f</string> |     <string name="rated_format" formatted="true">Оценето: %.1f</string> | ||||||
|     <string name="new_update_format" formatted="true">Пронајдена нова верзија на апликацијата!\n%s -> %s</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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Дома</string> |     <string name="title_home">Дома</string> | ||||||
|  | @ -35,7 +35,7 @@ | ||||||
|     <string name="pick_source">Извори</string> |     <string name="pick_source">Извори</string> | ||||||
|     <string name="pick_subtitle">Преводи</string> |     <string name="pick_subtitle">Преводи</string> | ||||||
|     <string name="reload_error">Повтори конекција…</string> |     <string name="reload_error">Повтори конекција…</string> | ||||||
|     <string name="result_go_back">Оди назад</string> |     <string name="go_back">Оди назад</string> | ||||||
|     <string name="play_episode">Пушти епизода</string> |     <string name="play_episode">Пушти епизода</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</string>--> |     <!--<string name="need_storage">Allow to download episodes</string>--> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ | ||||||
|     <string name="pick_source">സ്രോതസുകൾ</string> |     <string name="pick_source">സ്രോതസുകൾ</string> | ||||||
|     <string name="pick_subtitle">സബ്ടൈറ്റിലുകൾ</string> |     <string name="pick_subtitle">സബ്ടൈറ്റിലുകൾ</string> | ||||||
|     <string name="reload_error">വീണ്ടും കണക്ട് ചെയ്യുക…</string> |     <string name="reload_error">വീണ്ടും കണക്ട് ചെയ്യുക…</string> | ||||||
|     <string name="result_go_back">പിന്നോട്ട് പോകുക</string> |     <string name="go_back">പിന്നോട്ട് പോകുക</string> | ||||||
|     <string name="play_episode">എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക</string> |     <string name="play_episode">എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക</string> | ||||||
| 
 | 
 | ||||||
|     <string name="download">ഡൌൺലോഡ്</string> |     <string name="download">ഡൌൺലോഡ്</string> | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ | ||||||
|     <string name="pick_source">oha aauuh</string> |     <string name="pick_source">oha aauuh</string> | ||||||
|     <string name="pick_subtitle">ahooo ooo-ahah</string> |     <string name="pick_subtitle">ahooo ooo-ahah</string> | ||||||
|     <string name="reload_error">aaaghhahaaaaaaaaaaooh</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="episode_poster_img_des">oouuhahoooooo-ahahoooohh</string> | ||||||
|     <string name="play_episode">aaaaa oh ohaouuhhh</string> |     <string name="play_episode">aaaaa oh ohaouuhhh</string> | ||||||
|     <string name="need_storage">ahouuhhhaaaaa ahhaaaghh ahhh</string> |     <string name="need_storage">ahouuhhhaaaaa ahhaaaghh ahhh</string> | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ | ||||||
|     <string name="pick_source">Bronnen</string> |     <string name="pick_source">Bronnen</string> | ||||||
|     <string name="pick_subtitle">Ondertitels</string> |     <string name="pick_subtitle">Ondertitels</string> | ||||||
|     <string name="reload_error">Probeer verbinding opnieuw…</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="episode_poster_img_des">Afleveringsposter</string> | ||||||
|     <string name="play_episode">Aflevering afspelen</string> |     <string name="play_episode">Aflevering afspelen</string> | ||||||
|     <string name="need_storage">Toestaan om afleveringen te downloaden</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="player_speed_text_format" formatted="true">Avspillingshastighet (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Vurdert: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Hjem</string> |     <string name="title_home">Hjem</string> | ||||||
|  | @ -43,7 +42,7 @@ | ||||||
|     <string name="pick_source">Kilder</string> |     <string name="pick_source">Kilder</string> | ||||||
|     <string name="pick_subtitle">Undertekster</string> |     <string name="pick_subtitle">Undertekster</string> | ||||||
|     <string name="reload_error">Prøv tilkoblingen på nytt…</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="play_episode">Spille Episode</string> | ||||||
|     <!--<string name="need_storage">Tillat å laste ned episoder</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_source">Źródła</string> | ||||||
|     <string name="pick_subtitle">Napisy</string> |     <string name="pick_subtitle">Napisy</string> | ||||||
|     <string name="reload_error">Połącz ponownie…</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="play_episode">Odtwórz odcinek</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</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_main_poster_img_des">Główny plakat</string> | ||||||
|     <string name="home_next_random_img_des">Następny losowy</string> |     <string name="home_next_random_img_des">Następny losowy</string> | ||||||
|     <string name="go_back_img_des">Wstecz</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="home_change_provider_img_des">Zmień dostawcę</string> | ||||||
|     <string name="preview_background_img_des">Pogląd tła</string> |     <string name="preview_background_img_des">Pogląd tła</string> | ||||||
| </resources> | </resources> | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ | ||||||
|     <string name="player_speed_text_format" formatted="true">Velocidade (%.2fx)</string> |     <string name="player_speed_text_format" formatted="true">Velocidade (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Classificado: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Início</string> |     <string name="title_home">Início</string> | ||||||
|  | @ -46,7 +46,7 @@ | ||||||
|     <string name="pick_source">Origems</string> |     <string name="pick_source">Origems</string> | ||||||
|     <string name="pick_subtitle">Subtítulos</string> |     <string name="pick_subtitle">Subtítulos</string> | ||||||
|     <string name="reload_error">Reintentar conexão…</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="play_episode">Assistir Episódio</string> | ||||||
| 	 | 	 | ||||||
|     <string name="download">Descàrregar</string> |     <string name="download">Descàrregar</string> | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ | ||||||
|     <string name="player_speed_text_format" formatted="true">Viteză (%.2fx)</string> |     <string name="player_speed_text_format" formatted="true">Viteză (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Evaluat: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Principal</string> |     <string name="title_home">Principal</string> | ||||||
|  | @ -46,7 +46,7 @@ | ||||||
|     <string name="pick_source">Surse</string> |     <string name="pick_source">Surse</string> | ||||||
|     <string name="pick_subtitle">Subtitrare</string> |     <string name="pick_subtitle">Subtitrare</string> | ||||||
|     <string name="reload_error">Reîncercarea conexiunii…</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="play_episode">Redă episodul</string> | ||||||
|      |      | ||||||
| 	<string name="download">Descărcare</string> | 	<string name="download">Descărcare</string> | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ | ||||||
|     <string name="pick_source">Källor</string> |     <string name="pick_source">Källor</string> | ||||||
|     <string name="pick_subtitle">Undertexter</string> |     <string name="pick_subtitle">Undertexter</string> | ||||||
|     <string name="reload_error">Försök ansluta igen…</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="episode_poster_img_des">@string/result_poster_img_des</string> | ||||||
|     <string name="play_episode">Spela Avsnitt</string> |     <string name="play_episode">Spela Avsnitt</string> | ||||||
|     <string name="download">Ladda ner</string> |     <string name="download">Ladda ner</string> | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ | ||||||
|     <string name="player_speed_text_format" formatted="true">Bilis (%.2fx)</string> |     <string name="player_speed_text_format" formatted="true">Bilis (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Rated: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Home</string> |     <string name="title_home">Home</string> | ||||||
|  | @ -50,7 +49,7 @@ | ||||||
|     <string name="pick_source">Sources</string> |     <string name="pick_source">Sources</string> | ||||||
|     <string name="pick_subtitle">Subtitles</string> |     <string name="pick_subtitle">Subtitles</string> | ||||||
|     <string name="reload_error">Retry connection…</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="play_episode">I-play ang episode</string> | ||||||
|     <!--<string name="need_storage">Payagan sa Itabi</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="prefer_media_type_key" translatable="false">prefer_media_type_key</string> | ||||||
|     <string name="app_theme_key" translatable="false">app_theme_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 --> |     <!-- 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="result_poster_img_des">Afiş</string> | ||||||
|     <string name="search_poster_img_des">@string/result_poster_img_des</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="player_speed_text_format" formatted="true">Hız (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Puan: %.1f</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="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="app_name">CloudStream</string> | ||||||
|     <string name="title_home">Ana Sayfa</string> |     <string name="title_home">Ana Sayfa</string> | ||||||
|  | @ -89,7 +77,7 @@ | ||||||
|     <string name="pick_source">Kaynaklar</string> |     <string name="pick_source">Kaynaklar</string> | ||||||
|     <string name="pick_subtitle">Altyazılar</string> |     <string name="pick_subtitle">Altyazılar</string> | ||||||
|     <string name="reload_error">Yeniden bağlanmayı dene…</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="play_episode">Bölümü Oynat</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</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_source">Nguồn Phim</string> | ||||||
|     <string name="pick_subtitle">Phụ Đề</string> |     <string name="pick_subtitle">Phụ Đề</string> | ||||||
|     <string name="reload_error">Thử kết nối lại…</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="play_episode">Xem Tập Phim</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</string>--> |     <!--<string name="need_storage">Allow to download episodes</string>--> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -101,6 +101,7 @@ | ||||||
|         <item>Apple</item> |         <item>Apple</item> | ||||||
|         <item>Banana</item> |         <item>Banana</item> | ||||||
|         <item>Party</item> |         <item>Party</item> | ||||||
|  |         <item>Pink Pain</item> | ||||||
|     </string-array> |     </string-array> | ||||||
|     <string-array name="themes_overlay_names_values"> |     <string-array name="themes_overlay_names_values"> | ||||||
|         <item>Normal</item> |         <item>Normal</item> | ||||||
|  | @ -111,6 +112,7 @@ | ||||||
|         <item>GreenApple</item> |         <item>GreenApple</item> | ||||||
|         <item>Banana</item> |         <item>Banana</item> | ||||||
|         <item>Party</item> |         <item>Party</item> | ||||||
|  |         <item>Pink</item> | ||||||
|     </string-array> |     </string-array> | ||||||
| 
 | 
 | ||||||
|     <string-array name="themes_names"> |     <string-array name="themes_names"> | ||||||
|  |  | ||||||
|  | @ -62,4 +62,5 @@ | ||||||
|     <color name="colorPrimaryGreenApple">#48E484</color> |     <color name="colorPrimaryGreenApple">#48E484</color> | ||||||
|     <color name="colorPrimaryBanana">#E4D448</color> |     <color name="colorPrimaryBanana">#E4D448</color> | ||||||
|     <color name="colorPrimaryParty">#ea596e</color> |     <color name="colorPrimaryParty">#ea596e</color> | ||||||
|  |     <color name="colorPrimaryPink">#ff1493</color> | ||||||
| </resources> | </resources> | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
|     <string name="player_resize_enabled_key" translatable="false">player_resize_enabled_key</string> |     <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="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_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="swipe_vertical_enabled_key" translatable="false">swipe_vertical_enabled_key</string> | ||||||
|     <string name="display_sub_key" translatable="false">display_sub_key</string> |     <string name="display_sub_key" translatable="false">display_sub_key</string> | ||||||
|     <string name="show_fillers_key" translatable="false">show_fillers_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="player_speed_text_format" formatted="true">Speed (%.2fx)</string> | ||||||
|     <string name="rated_format" formatted="true">Rated: %.1f</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="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="duration_format" formatted="true">%d min</string> | ||||||
| 
 | 
 | ||||||
|     <string name="app_name">CloudStream</string> |     <string name="app_name">CloudStream</string> | ||||||
|  | @ -94,7 +95,7 @@ | ||||||
|     <string name="pick_source">Sources</string> |     <string name="pick_source">Sources</string> | ||||||
|     <string name="pick_subtitle">Subtitles</string> |     <string name="pick_subtitle">Subtitles</string> | ||||||
|     <string name="reload_error">Retry connection…</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="play_episode">Play Episode</string> | ||||||
|     <!--<string name="need_storage">Allow to download episodes</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">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="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_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 name="double_tap_to_seek_settings_des">Tap twice on the right or left side to seek forwards or backwards | ||||||
|     </string> |     </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">Use system brightness</string> | ||||||
|     <string name="use_system_brightness_settings_des">Use system brightness in the app player instead of a dark |     <string name="use_system_brightness_settings_des">Use system brightness in the app player instead of a dark | ||||||
|         overlay |         overlay | ||||||
|  | @ -226,6 +229,8 @@ | ||||||
|     <string name="cancel" translatable="false">@string/sort_cancel</string> |     <string name="cancel" translatable="false">@string/sort_cancel</string> | ||||||
|     <string name="pause">Pause</string> |     <string name="pause">Pause</string> | ||||||
|     <string name="resume">Resume</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="delete_message" formatted="true">This will permanently delete %s\nAre you sure?</string> | ||||||
| 
 | 
 | ||||||
|     <string name="status_ongoing">Ongoing</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="subtitles_example_text">The quick brown fox jumps over the lazy dog</string> | ||||||
| 
 | 
 | ||||||
|     <string name="tab_recommended">Recommended</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="player_load_subtitles">Load from file</string> | ||||||
|  |     <string name="downloaded_file">Downloaded file</string> | ||||||
| </resources> | </resources> | ||||||
|  |  | ||||||
|  | @ -165,6 +165,15 @@ | ||||||
|         <item name="android:colorAccent">@color/colorPrimaryParty</item> |         <item name="android:colorAccent">@color/colorPrimaryParty</item> | ||||||
|     </style> |     </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"> |     <style name="LoadedStyle"> | ||||||
|         <item name="android:navigationBarColor">?attr/primaryGrayBackground</item> |         <item name="android:navigationBarColor">?attr/primaryGrayBackground</item> | ||||||
|         <item name="android:windowBackground">?attr/primaryBlackBackground</item> |         <item name="android:windowBackground">?attr/primaryBlackBackground</item> | ||||||
|  | @ -323,6 +332,19 @@ | ||||||
|         <item name="rippleColor">?attr/textColor</item> |         <item name="rippleColor">?attr/textColor</item> | ||||||
|     </style> |     </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"> |     <style name="RoundedSelectableButtonIcon" parent="RoundedSelectableButton"> | ||||||
|         <item name="minWidth">0dp</item> |         <item name="minWidth">0dp</item> | ||||||
|         <item name="iconTint">?attr/textColor</item> |         <item name="iconTint">?attr/textColor</item> | ||||||
|  |  | ||||||
|  | @ -60,6 +60,14 @@ | ||||||
|                 android:summary="@string/double_tap_to_seek_settings_des" |                 android:summary="@string/double_tap_to_seek_settings_des" | ||||||
|                 app:defaultValue="false" |                 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 |         <SwitchPreference | ||||||
|                 android:icon="@drawable/ic_baseline_brightness_7_24" |                 android:icon="@drawable/ic_baseline_brightness_7_24" | ||||||
|                 app:key="@string/use_system_brightness_key" |                 app:key="@string/use_system_brightness_key" | ||||||
|  | @ -67,6 +75,7 @@ | ||||||
|                 android:summary="@string/use_system_brightness_settings_des" |                 android:summary="@string/use_system_brightness_settings_des" | ||||||
|                 app:defaultValue="false" |                 app:defaultValue="false" | ||||||
|         /> |         /> | ||||||
|  |         --> | ||||||
|     </PreferenceCategory> |     </PreferenceCategory> | ||||||
|     <PreferenceCategory |     <PreferenceCategory | ||||||
|             android:key="general" |             android:key="general" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue