2022-01-07 19:27:25 +00:00
package com.lagradost.cloudstream3
2022-12-06 18:41:09 +00:00
import android.Manifest
2022-01-07 19:27:25 +00:00
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
2022-04-03 15:00:50 +00:00
import android.util.Log
2022-01-07 19:27:25 +00:00
import android.view.*
2023-07-30 03:05:13 +00:00
import android.view.View.NO_ID
2022-01-07 19:27:25 +00:00
import android.widget.TextView
import android.widget.Toast
2022-10-08 20:29:17 +00:00
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
2022-08-08 12:37:46 +00:00
import androidx.annotation.MainThread
2022-01-07 19:27:25 +00:00
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
2022-12-06 18:41:09 +00:00
import androidx.core.content.ContextCompat
2023-08-04 03:37:41 +00:00
import androidx.core.view.children
2022-01-07 19:27:25 +00:00
import androidx.preference.PreferenceManager
import com.google.android.gms.cast.framework.CastSession
2023-08-04 03:37:41 +00:00
import com.google.android.material.chip.ChipGroup
import com.google.android.material.navigationrail.NavigationRailView
2022-10-08 20:29:17 +00:00
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.player.PlayerEventType
2022-10-08 20:29:17 +00:00
import com.lagradost.cloudstream3.ui.result.ResultFragment
2022-08-07 23:03:54 +00:00
import com.lagradost.cloudstream3.ui.result.UiText
2022-08-28 23:52:15 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
2023-07-28 02:18:28 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
2022-10-08 20:29:17 +00:00
import com.lagradost.cloudstream3.utils.DataStoreHelper
2022-01-07 19:27:25 +00:00
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
2022-07-27 23:38:20 +00:00
import org.schabi.newpipe.extractor.NewPipe
2023-07-17 01:32:41 +00:00
import java.lang.ref.WeakReference
2022-01-07 19:27:25 +00:00
import java.util.*
2023-08-04 03:37:41 +00:00
enum class FocusDirection {
Start ,
End ,
Up ,
Down ,
}
2022-01-07 19:27:25 +00:00
object CommonActivity {
2023-07-17 01:32:41 +00:00
private var _activity : WeakReference < Activity > ? = null
var activity
get ( ) = _activity ?. get ( )
private set ( value ) {
_activity = WeakReference ( value )
}
2022-08-08 12:37:46 +00:00
@MainThread
2022-01-07 19:27:25 +00:00
fun Activity ?. getCastSession ( ) : CastSession ? {
return ( this as MainActivity ? ) ?. mSessionManager ?. currentCastSession
}
2022-10-08 20:29:17 +00:00
2022-01-07 19:27:25 +00:00
var canEnterPipMode : Boolean = false
var canShowPipMode : Boolean = false
var isInPIPMode : Boolean = false
val onColorSelectedEvent = Event < Pair < Int , Int > > ( )
val onDialogDismissedEvent = Event < Int > ( )
var playerEventListener : ( ( PlayerEventType ) -> Unit ) ? = null
2022-01-18 00:24:23 +00:00
var keyEventListener : ( ( Pair < KeyEvent ? , Boolean > ) -> Boolean ) ? = null
2022-01-07 19:27:25 +00:00
var currentToast : Toast ? = null
2023-07-17 01:32:41 +00:00
fun showToast ( @StringRes message : Int , duration : Int ? = null ) {
val act = activity ?: return
act . runOnUiThread {
showToast ( act , act . getString ( message ) , duration )
}
}
fun showToast ( message : String ? , duration : Int ? = null ) {
val act = activity ?: return
act . runOnUiThread {
showToast ( act , message , duration )
}
}
fun showToast ( message : UiText ? , duration : Int ? = null ) {
val act = activity ?: return
if ( message == null ) return
act . runOnUiThread {
2023-07-24 02:02:05 +00:00
showToast ( act , message . asString ( act ) , duration )
2023-07-17 01:32:41 +00:00
}
}
@MainThread
2022-08-07 23:03:54 +00:00
fun showToast ( act : Activity ? , text : UiText , duration : Int ) {
if ( act == null ) return
text . asStringNull ( act ) ?. let {
showToast ( act , it , duration )
}
}
2022-11-06 19:16:48 +00:00
/** duration is Toast.LENGTH_SHORT if null*/
2022-11-05 18:54:04 +00:00
@MainThread
2022-11-06 19:16:48 +00:00
fun showToast ( act : Activity ? , @StringRes message : Int , duration : Int ? = null ) {
2022-01-07 19:27:25 +00:00
if ( act == null ) return
showToast ( act , act . getString ( message ) , duration )
}
2022-04-03 15:00:50 +00:00
const val TAG = " COMPACT "
2022-01-07 19:27:25 +00:00
/** duration is Toast.LENGTH_SHORT if null*/
2022-11-05 18:54:04 +00:00
@MainThread
2022-01-07 19:27:25 +00:00
fun showToast ( act : Activity ? , message : String ? , duration : Int ? = null ) {
2022-04-03 15:00:50 +00:00
if ( act == null || message == null ) {
Log . w ( TAG , " invalid showToast act = $act message = $message " )
return
}
Log . i ( TAG , " showToast = $message " )
2022-01-07 19:27:25 +00:00
try {
currentToast ?. cancel ( )
} catch ( e : Exception ) {
2022-04-03 15:00:50 +00:00
logError ( e )
2022-01-07 19:27:25 +00:00
}
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
2022-04-06 15:16:08 +00:00
//https://github.com/PureWriter/ToastCompat
2022-01-07 19:27:25 +00:00
toast . show ( )
currentToast = toast
} catch ( e : Exception ) {
2022-04-03 15:00:50 +00:00
logError ( e )
2022-01-07 19:27:25 +00:00
}
}
2022-11-29 19:45:00 +00:00
/ * *
* Not all languages can be fetched from locale with a code .
* This map allows sidestepping the default Locale ( languageCode )
* when setting the app language .
* * /
val appLanguageExceptions = hashMapOf (
2022-12-25 18:56:59 +00:00
" zh-rTW " to Locale . TRADITIONAL _CHINESE
2022-11-29 19:45:00 +00:00
)
2022-01-07 19:27:25 +00:00
fun setLocale ( context : Context ? , languageCode : String ? ) {
if ( context == null || languageCode == null ) return
2022-11-29 19:45:00 +00:00
val locale = appLanguageExceptions [ languageCode ] ?: Locale ( languageCode )
2022-01-07 19:27:25 +00:00
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 )
}
2022-10-08 20:29:17 +00:00
fun init ( act : ComponentActivity ? ) {
2022-01-07 19:27:25 +00:00
if ( act == null ) return
2023-07-17 01:32:41 +00:00
activity = act
2022-01-07 19:27:25 +00:00
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
//https://developer.android.com/guide/topics/ui/picture-in-picture
canShowPipMode =
2022-04-10 13:57:02 +00:00
Build . VERSION . SDK _INT >= Build . VERSION_CODES . N && // OS SUPPORT
2022-01-07 19:27:25 +00:00
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 ( )
2022-08-28 23:52:15 +00:00
act . updateTv ( )
2022-07-27 23:38:20 +00:00
NewPipe . init ( DownloaderTestImpl . getInstance ( ) )
2022-10-08 20:29:17 +00:00
for ( resumeApp in resumeApps ) {
resumeApp . launcher =
act . registerForActivityResult ( ActivityResultContracts . StartActivityForResult ( ) ) { result ->
val resultCode = result . resultCode
val data = result . data
if ( resultCode == AppCompatActivity . RESULT _OK && data != null && resumeApp . position != null && resumeApp . duration != null ) {
2022-11-30 20:23:19 +00:00
val pos = resumeApp . getPosition ( data )
val dur = resumeApp . getDuration ( data )
2022-10-08 20:29:17 +00:00
if ( dur > 0L && pos > 0L )
DataStoreHelper . setViewPos ( getKey ( resumeApp . lastId ) , pos , dur )
removeKey ( resumeApp . lastId )
ResultFragment . updateUI ( )
}
}
}
2022-12-06 18:41:09 +00:00
// Ask for notification permissions on Android 13
if ( Build . VERSION . SDK _INT >= Build . VERSION_CODES . TIRAMISU &&
ContextCompat . checkSelfPermission (
act ,
Manifest . permission . POST _NOTIFICATIONS
) != PackageManager . PERMISSION _GRANTED
) {
val requestPermissionLauncher = act . registerForActivityResult (
ActivityResultContracts . RequestPermission ( )
) { isGranted : Boolean ->
Log . d ( TAG , " Notification permission: $isGranted " )
}
requestPermissionLauncher . launch (
Manifest . permission . POST _NOTIFICATIONS
)
}
2022-01-07 19:27:25 +00:00
}
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 ( )
}
}
2022-01-18 00:24:23 +00:00
fun loadThemes ( act : Activity ? ) {
if ( act == null ) return
2022-01-07 19:27:25 +00:00
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
2022-09-23 17:09:16 +00:00
" Monet " -> if ( Build . VERSION . SDK _INT >= Build . VERSION_CODES . S )
2022-10-08 20:29:17 +00:00
R . style . MonetMode else R . style . AppTheme
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
else -> R . style . AppTheme
}
val currentOverlayTheme =
when ( settingsManager . getString ( act . getString ( R . string . primary _color _key ) , " Normal " ) ) {
" Normal " -> R . style . OverlayPrimaryColorNormal
2022-04-09 21:07:52 +00:00
" CarnationPink " -> R . style . OverlayPrimaryColorCarnationPink
" DarkGreen " -> R . style . OverlayPrimaryColorDarkGreen
" Maroon " -> R . style . OverlayPrimaryColorMaroon
" NavyBlue " -> R . style . OverlayPrimaryColorNavyBlue
" Grey " -> R . style . OverlayPrimaryColorGrey
" White " -> R . style . OverlayPrimaryColorWhite
" Brown " -> R . style . OverlayPrimaryColorBrown
2022-01-07 19:27:25 +00:00
" 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
2022-09-23 17:09:16 +00:00
" Monet " -> if ( Build . VERSION . SDK _INT >= Build . VERSION_CODES . S )
R . style . OverlayPrimaryColorMonet else R . style . OverlayPrimaryColorNormal
2023-07-17 01:32:41 +00:00
2022-09-23 17:09:16 +00:00
" Monet2 " -> if ( Build . VERSION . SDK _INT >= Build . VERSION_CODES . S )
R . style . OverlayPrimaryColorMonetTwo else R . style . OverlayPrimaryColorNormal
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
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
}
2023-07-30 03:05:13 +00:00
/ * * because we want closes find , aka when multiple have the same id , we go to parent
until the correct one is found * /
private fun localLook ( from : View , id : Int ) : View ? {
if ( id == NO _ID ) return null
var currentLook : View = from
2023-08-02 19:00:04 +00:00
// limit to 15 look depth
for ( i in 0. . 15 ) {
2023-07-30 03:05:13 +00:00
currentLook . findViewById < View ? > ( id ) ?. let { return it }
currentLook = ( currentLook . parent as ? View ) ?: break
}
return null
}
/ * var currentLook : View = view
while ( true ) {
val tmpNext = currentLook . findViewById < View ? > ( nextId )
if ( tmpNext != null ) {
next = tmpNext
break
}
currentLook = currentLook . parent as ? View ?: break
} * /
2023-08-04 03:37:41 +00:00
/** skips the initial stage of searching for an id using the view, see getNextFocus for specification */
fun continueGetNextFocus (
root : Any ? ,
view : View ,
direction : FocusDirection ,
nextId : Int ,
depth : Int = 0
) : View ? {
if ( nextId == NO _ID ) return null
// do an initial search for the view, in case the localLook is too deep we can use this as
// an early break and backup view
var next =
when ( root ) {
is Activity -> root . findViewById ( nextId )
is View -> root . rootView . findViewById < View ? > ( nextId )
else -> null
} ?: return null
next = localLook ( view , nextId ) ?: next
// if cant focus but visible then break and let android decide
// the exception if is the view is a parent and has children that wants focus
val hasChildrenThatWantsFocus = ( next as ? ViewGroup ) ?. let { parent ->
parent . descendantFocusability == ViewGroup . FOCUS _AFTER _DESCENDANTS && parent . childCount > 0
} ?: false
if ( ! next . isFocusable && next . isShown && ! hasChildrenThatWantsFocus ) return null
// if not shown then continue because we will "skip" over views to get to a replacement
if ( ! next . isShown ) {
// we don't want a while true loop, so we let android decide if we find a recursive view
if ( next == view ) return null
return getNextFocus ( root , next , direction , depth + 1 )
}
( when ( next ) {
is ChipGroup -> {
next . children . firstOrNull { it . isFocusable && it . isShown }
}
is NavigationRailView -> {
next . findViewById ( next . selectedItemId ) ?: next . findViewById ( R . id . navigation _home )
}
else -> null
} ) ?. let {
return it
}
// nothing wrong with the view found, return it
return next
}
2023-07-30 03:05:13 +00:00
/ * * recursively looks for a next focus up to a depth of 10 ,
* this is used to override the normal shit focus system
* because this application has a lot of invisible views that messes with some tv devices * /
2023-08-04 03:37:41 +00:00
fun getNextFocus (
root : Any ? ,
2022-01-07 19:27:25 +00:00
view : View ? ,
direction : FocusDirection ,
depth : Int = 0
2023-07-28 02:18:28 +00:00
) : View ? {
// if input is invalid let android decide + depth test to not crash if loop is found
2023-08-04 03:37:41 +00:00
if ( view == null || depth >= 10 || root == null ) {
2022-01-07 19:27:25 +00:00
return null
}
2023-07-30 03:05:13 +00:00
var nextId = when ( direction ) {
2023-07-28 02:18:28 +00:00
FocusDirection . Start -> {
if ( view . isRtl ( ) )
view . nextFocusRightId
else
view . nextFocusLeftId
2022-01-07 19:27:25 +00:00
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
FocusDirection . Up -> {
view . nextFocusUpId
}
2023-07-17 01:32:41 +00:00
2023-07-28 02:18:28 +00:00
FocusDirection . End -> {
if ( view . isRtl ( ) )
view . nextFocusLeftId
else
view . nextFocusRightId
2022-01-07 19:27:25 +00:00
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
FocusDirection . Down -> {
view . nextFocusDownId
}
}
2023-07-30 03:05:13 +00:00
if ( nextId == NO _ID ) {
// if not specified then use forward id
nextId = view . nextFocusForwardId
// if view is still not found to next focus then return and let android decide
2023-08-02 19:00:04 +00:00
if ( nextId == NO _ID )
return null
2023-07-30 03:05:13 +00:00
}
2023-08-04 03:37:41 +00:00
return continueGetNextFocus ( root , view , direction , nextId , depth )
2022-01-07 19:27:25 +00:00
}
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
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
KeyEvent . KEYCODE _A , KeyEvent . KEYCODE _MEDIA _SKIP _BACKWARD , KeyEvent . KEYCODE _MEDIA _REWIND -> {
PlayerEventType . SeekBack
}
2023-07-17 01:32:41 +00:00
2022-08-05 23:41:35 +00:00
KeyEvent . KEYCODE _MEDIA _NEXT , KeyEvent . KEYCODE _BUTTON _R1 , KeyEvent . KEYCODE _N -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . NextEpisode
}
2023-07-17 01:32:41 +00:00
2022-08-05 23:41:35 +00:00
KeyEvent . KEYCODE _MEDIA _PREVIOUS , KeyEvent . KEYCODE _BUTTON _L1 , KeyEvent . KEYCODE _B -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . PrevEpisode
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
KeyEvent . KEYCODE _MEDIA _PAUSE -> {
PlayerEventType . Pause
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
KeyEvent . KEYCODE _MEDIA _PLAY , KeyEvent . KEYCODE _BUTTON _START -> {
PlayerEventType . Play
}
2023-07-17 01:32:41 +00:00
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _L , KeyEvent . KEYCODE _NUMPAD _7 , KeyEvent . KEYCODE _7 -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . Lock
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
KeyEvent . KEYCODE _H , KeyEvent . KEYCODE _MENU -> {
PlayerEventType . ToggleHide
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
KeyEvent . KEYCODE _M , KeyEvent . KEYCODE _VOLUME _MUTE -> {
PlayerEventType . ToggleMute
}
2023-07-17 01:32:41 +00:00
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _S , KeyEvent . KEYCODE _NUMPAD _9 , KeyEvent . KEYCODE _9 -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . ShowMirrors
}
2022-06-08 18:15:24 +00:00
// OpenSubtitles shortcut
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _O , KeyEvent . KEYCODE _NUMPAD _8 , KeyEvent . KEYCODE _8 -> {
2022-06-08 18:15:24 +00:00
PlayerEventType . SearchSubtitlesOnline
}
2023-07-17 01:32:41 +00:00
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _E , KeyEvent . KEYCODE _NUMPAD _3 , KeyEvent . KEYCODE _3 -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . ShowSpeed
}
2023-07-17 01:32:41 +00:00
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _R , KeyEvent . KEYCODE _NUMPAD _0 , KeyEvent . KEYCODE _0 -> {
2022-01-07 19:27:25 +00:00
PlayerEventType . Resize
}
2023-07-17 01:32:41 +00:00
2022-09-08 15:35:56 +00:00
KeyEvent . KEYCODE _C , KeyEvent . KEYCODE _NUMPAD _4 , KeyEvent . KEYCODE _4 -> {
2022-08-05 23:41:35 +00:00
PlayerEventType . SkipOp
}
2023-07-17 01:32:41 +00:00
2022-11-04 23:36:27 +00:00
KeyEvent . KEYCODE _V , KeyEvent . KEYCODE _NUMPAD _5 , KeyEvent . KEYCODE _5 -> {
PlayerEventType . SkipCurrentChapter
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
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
}
2023-07-17 01:32:41 +00:00
2022-01-07 19:27:25 +00:00
else -> null
} ?. let { playerEvent ->
playerEventListener ?. invoke ( playerEvent )
}
//when (keyCode) {
// KeyEvent.KEYCODE_DPAD_CENTER -> {
// println("DPAD PRESSED")
// }
//}
}
2023-07-30 03:05:13 +00:00
/** overrides focus and custom key events */
2022-01-07 19:27:25 +00:00
fun dispatchKeyEvent ( act : Activity ? , event : KeyEvent ? ) : Boolean ? {
if ( act == null ) return null
2023-07-24 02:02:05 +00:00
val currentFocus = act . currentFocus
2022-01-07 19:27:25 +00:00
event ?. keyCode ?. let { keyCode ->
2023-07-24 02:02:05 +00:00
if ( currentFocus == null || event . action != KeyEvent . ACTION _DOWN ) return @let
2023-07-28 02:18:28 +00:00
val nextView = when ( keyCode ) {
2023-07-24 02:02:05 +00:00
KeyEvent . KEYCODE _DPAD _LEFT -> getNextFocus (
act ,
currentFocus ,
2023-07-28 02:18:28 +00:00
FocusDirection . Start
2023-07-24 02:02:05 +00:00
)
KeyEvent . KEYCODE _DPAD _RIGHT -> getNextFocus (
act ,
currentFocus ,
2023-07-28 02:18:28 +00:00
FocusDirection . End
2023-07-24 02:02:05 +00:00
)
KeyEvent . KEYCODE _DPAD _UP -> getNextFocus (
act ,
currentFocus ,
FocusDirection . Up
)
KeyEvent . KEYCODE _DPAD _DOWN -> getNextFocus (
act ,
currentFocus ,
FocusDirection . Down
)
else -> null
}
2023-08-04 03:37:41 +00:00
// println("NEXT FOCUS : $nextView")
2023-07-28 02:18:28 +00:00
if ( nextView != null ) {
nextView . requestFocus ( )
keyEventListener ?. invoke ( Pair ( event , true ) )
return true
2022-01-07 19:27:25 +00:00
}
2023-07-24 02:02:05 +00:00
2023-07-30 03:05:13 +00:00
if ( keyCode == KeyEvent . KEYCODE _DPAD _CENTER &&
( act . currentFocus is SearchView || act . currentFocus is SearchView . SearchAutoComplete )
) {
2023-07-24 02:02:05 +00:00
UIHelper . showInputMethod ( act . currentFocus ?. findFocus ( ) )
}
//println("Keycode: $keyCode")
//showToast(
// this,
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
// Toast.LENGTH_LONG
//)
2022-01-07 19:27:25 +00:00
}
2023-07-30 03:05:13 +00:00
// if someone else want to override the focus then don't handle the event as it is already
// consumed. used in video player
2022-01-18 00:24:23 +00:00
if ( keyEventListener ?. invoke ( Pair ( event , false ) ) == true ) {
2022-01-07 19:27:25 +00:00
return true
}
return null
}
2022-11-29 19:45:00 +00:00
}