Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lsongdev committed Aug 22, 2024
1 parent da06a75 commit a6d6d8c
Show file tree
Hide file tree
Showing 31 changed files with 233 additions and 518 deletions.
Binary file added Ducky.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added DuckyTransparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<application
android:name=".MyTVApplication"
android:allowBackup="true"
android:banner="@drawable/ic_banner"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
Expand All @@ -26,7 +27,7 @@
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".LeanbackActivity"
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.MyTV">
<intent-filter>
Expand Down
13 changes: 0 additions & 13 deletions app/src/main/java/me/lsong/mytv/AppGlobal.kt

This file was deleted.

18 changes: 0 additions & 18 deletions app/src/main/java/me/lsong/mytv/BootReceiver.kt

This file was deleted.

52 changes: 32 additions & 20 deletions app/src/main/java/me/lsong/mytv/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package me.lsong.mytv

import android.app.PictureInPictureParams
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Rational
Expand Down Expand Up @@ -34,28 +36,16 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.debounce
import me.lsong.mytv.ui.components.LeanbackPadding
import me.lsong.mytv.ui.LoadingScreen
import me.lsong.mytv.ui.components.LeanbackPadding
import me.lsong.mytv.ui.theme.LeanbackTheme
import me.lsong.mytv.ui.toast.LeanbackToastScreen
import me.lsong.mytv.ui.toast.LeanbackToastState
import me.lsong.mytv.ui.utils.HttpServer
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.HttpServer
import me.lsong.mytv.utils.Settings
import kotlin.system.exitProcess

class LeanbackActivity : ComponentActivity() {
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
if (!SP.uiPipMode) return

enterPictureInPictureMode(
PictureInPictureParams.Builder()
.setAspectRatio(Rational(16, 9))
.build()
)
super.onUserLeaveHint()
}

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
Expand Down Expand Up @@ -88,21 +78,44 @@ class LeanbackActivity : ComponentActivity() {
}
}

// Check if the device is a TV
if (isTVDevice()) {
// No need to force orientation for TV
} else {
// Force landscape mode on non-TV devices
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
}


HttpServer.start(applicationContext, showToast = {
LeanbackToastState.I.showToast(it, id = "httpServer")
})
}
}

private fun isTVDevice(): Boolean {
return (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) ||
packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
}

override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
if (!Settings.uiPipMode) return

enterPictureInPictureMode(
PictureInPictureParams.Builder()
.setAspectRatio(Rational(16, 9))
.build()
)
super.onUserLeaveHint()
}
}

@Composable
fun LeanbackApp(
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
) {
val context = LocalContext.current
val doubleBackPressedExitState = rememberLeanbackDoubleBackPressedExitState()

LeanbackToastScreen()
LoadingScreen(
modifier = modifier,
Expand All @@ -117,7 +130,6 @@ fun LeanbackApp(
)
}


/**
* 退出应用二次确认
*/
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/me/lsong/mytv/MyTVApplication.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package me.lsong.mytv

import android.app.Application
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings

class MyTVApplication : Application() {
override fun onCreate() {
super.onCreate()

UnsafeTrustManager.enableUnsafeTrustManager()
AppGlobal.cacheDir = applicationContext.cacheDir
SP.init(applicationContext)
Settings.init(applicationContext)
}
}
10 changes: 5 additions & 5 deletions app/src/main/java/me/lsong/mytv/ui/LoadingScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ import io.github.alexzhirkevich.qrose.rememberQrCodePainter
import me.lsong.mytv.R
import me.lsong.mytv.rememberLeanbackChildPadding
import me.lsong.mytv.ui.components.LeanbackVisible
import me.lsong.mytv.ui.settings.LeanbackSettingsScreen
import me.lsong.mytv.ui.settings.MyTvSettingsScreen
import me.lsong.mytv.ui.theme.LeanbackTheme
import me.lsong.mytv.ui.utils.HttpServer
import me.lsong.mytv.utils.HttpServer
import me.lsong.mytv.utils.Constants

@Composable
Expand All @@ -69,8 +69,6 @@ fun LoadingScreen(
is LeanbackMainUiState.Error -> LeanbackMainSettingsHandle(onBackPressed = onBackPressed) {
LeanbackMainScreenError({ s.message })
}

else -> {}
}
}

Expand Down Expand Up @@ -219,6 +217,8 @@ private fun LeanbackMainSettingsHandle(
LeanbackBackPressHandledArea(onBackPressed = {
if (showSettings) {
showSettings = false
onBackPressed()
onBackPressed()
} else {
showSettings = true
}
Expand All @@ -230,7 +230,7 @@ private fun LeanbackMainSettingsHandle(
) {
content()
LeanbackVisible({ showSettings }) {
LeanbackSettingsScreen()
MyTvSettingsScreen()
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions app/src/main/java/me/lsong/mytv/ui/MainContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import me.lsong.mytv.iptv.TVGroupList
import me.lsong.mytv.ui.components.LeanbackVisible
import me.lsong.mytv.ui.components.LeanbackMonitorScreen
import me.lsong.mytv.ui.player.MyTvVideoScreen
import me.lsong.mytv.ui.settings.LeanbackSettingsViewModel
import me.lsong.mytv.ui.player.rememberLeanbackVideoPlayerState
import me.lsong.mytv.ui.settings.MyTvSettingsViewModel
import me.lsong.mytv.ui.widgets.MyTvMenu
import me.lsong.mytv.ui.widgets.MyTvNowPlaying
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings
import me.lsong.mytv.utils.handleLeanbackDragGestures
import me.lsong.mytv.utils.handleLeanbackKeyEvents

Expand All @@ -36,16 +36,16 @@ fun LeanbackMainContent(
onBackPressed: () -> Unit = {},
epgList: EpgList = EpgList(),
groupList: TVGroupList = TVGroupList(),
settingsViewModel: LeanbackSettingsViewModel = viewModel(),
settingsViewModel: MyTvSettingsViewModel = viewModel(),
) {
val configuration = LocalConfiguration.current
val videoPlayerState = rememberLeanbackVideoPlayerState(
defaultAspectRatioProvider = {
when (settingsViewModel.videoPlayerAspectRatio) {
SP.VideoPlayerAspectRatio.ORIGINAL -> null
SP.VideoPlayerAspectRatio.SIXTEEN_NINE -> 16f / 9f
SP.VideoPlayerAspectRatio.FOUR_THREE -> 4f / 3f
SP.VideoPlayerAspectRatio.AUTO -> {
Settings.VideoPlayerAspectRatio.ORIGINAL -> null
Settings.VideoPlayerAspectRatio.SIXTEEN_NINE -> 16f / 9f
Settings.VideoPlayerAspectRatio.FOUR_THREE -> 4f / 3f
Settings.VideoPlayerAspectRatio.AUTO -> {
configuration.screenHeightDp.toFloat() / configuration.screenWidthDp.toFloat()
}
}
Expand Down
14 changes: 7 additions & 7 deletions app/src/main/java/me/lsong/mytv/ui/MainContentState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import me.lsong.mytv.iptv.TVGroupList.Companion.findChannelIndex
import me.lsong.mytv.utils.Constants
import me.lsong.mytv.ui.player.LeanbackVideoPlayerState
import me.lsong.mytv.ui.player.rememberLeanbackVideoPlayerState
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings
import kotlin.math.max

@Stable
Expand Down Expand Up @@ -52,7 +52,7 @@ class MainContentState(
get() = tvGroupList.findChannelIndex(_currentChannel)

init {
changeCurrentChannel(tvGroupList.channels.getOrElse(SP.iptvLastIptvIdx) {
changeCurrentChannel(tvGroupList.channels.getOrElse(Settings.iptvLastIptvIdx) {
tvGroupList.firstOrNull()?.channels?.firstOrNull() ?: TVChannel()
})

Expand All @@ -67,7 +67,7 @@ class MainContentState(
}

// 记忆可播放的域名
SP.iptvPlayableHostList += getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
Settings.iptvPlayableHostList += getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
}

videoPlayerState.onError {
Expand All @@ -76,7 +76,7 @@ class MainContentState(
}

// 从记忆中删除不可播放的域名
SP.iptvPlayableHostList -= getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
Settings.iptvPlayableHostList -= getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
}

videoPlayerState.onCutoff {
Expand All @@ -102,17 +102,17 @@ class MainContentState(
// isChannelInfoVisible = false
if (channel == _currentChannel && urlIdx == null) return
if (channel == _currentChannel && urlIdx != _currentIptvUrlIdx) {
SP.iptvPlayableHostList -= getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
Settings.iptvPlayableHostList -= getUrlHost(_currentChannel.urls[_currentIptvUrlIdx])
}
// _isTempPanelVisible = true

_currentChannel = channel
SP.iptvLastIptvIdx = currentChannelIndex
Settings.iptvLastIptvIdx = currentChannelIndex

_currentIptvUrlIdx = if (urlIdx == null) {
// 优先从记忆中选择可播放的域名
max(0, _currentChannel.urls.indexOfFirst {
SP.iptvPlayableHostList.contains(getUrlHost(it))
Settings.iptvPlayableHostList.contains(getUrlHost(it))
})
} else {
(urlIdx + _currentChannel.urls.size) % _currentChannel.urls.size
Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/me/lsong/mytv/ui/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import me.lsong.mytv.iptv.TVSource
import me.lsong.mytv.epg.EpgRepository
import me.lsong.mytv.iptv.IptvRepository
import me.lsong.mytv.utils.Constants
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings

class MainViewModel : ViewModel() {
private val iptvRepository = IptvRepository()
Expand All @@ -46,8 +46,8 @@ class MainViewModel : ViewModel() {
// "https://raw.githubusercontent.com/fanmingming/live/main/tv/m3u/index.m3u",
// )

if (SP.iptvSourceUrls.isNotEmpty()) {
iptvUrls += SP.iptvSourceUrls
if (Settings.iptvSourceUrls.isNotEmpty()) {
iptvUrls += Settings.iptvSourceUrls
}
if (iptvUrls.isEmpty()) {
iptvUrls += Constants.IPTV_SOURCE_URL
Expand Down Expand Up @@ -75,7 +75,7 @@ class MainViewModel : ViewModel() {
}
.catch { error ->
_uiState.value = LeanbackMainUiState.Error(error.message)
SP.iptvSourceUrlHistoryList -= iptvUrls.toList()
Settings.iptvSourceUrlHistoryList -= iptvUrls.toList()
}
.collect { result ->
when (result) {
Expand All @@ -89,7 +89,7 @@ class MainViewModel : ViewModel() {
tvGroupList = result.groupList,
epgList = result.epgList
)
SP.iptvSourceUrlHistoryList += iptvUrls.toList()
Settings.iptvSourceUrlHistoryList += iptvUrls.toList()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fun MyTvChannelItem(
),
),
selected = isSelectedProvider(),
onClick = { },
onClick = { onSelected() },
leadingContent = {
if (iptv.icon != null) {
androidx.tv.material3.Icon(iptv.icon, iptv.title)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings
import androidx.media3.common.PlaybackException as Media3PlaybackException

@OptIn(UnstableApi::class)
Expand All @@ -48,9 +48,9 @@ class LeanbackMedia3VideoPlayer(
private fun prepare(uri: Uri, contentType: Int? = null) {
val dataSourceFactory =
DefaultDataSource.Factory(context, DefaultHttpDataSource.Factory().apply {
setUserAgent(SP.videoPlayerUserAgent)
setConnectTimeoutMs(SP.videoPlayerLoadTimeout.toInt())
setReadTimeoutMs(SP.videoPlayerLoadTimeout.toInt())
setUserAgent(Settings.videoPlayerUserAgent)
setConnectTimeoutMs(Settings.videoPlayerLoadTimeout.toInt())
setReadTimeoutMs(Settings.videoPlayerLoadTimeout.toInt())
setKeepPostFor302Redirects(true)
setAllowCrossProtocolRedirects(true)
})
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/me/lsong/mytv/ui/player/VideoPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.lsong.mytv.utils.SP
import me.lsong.mytv.utils.Settings

abstract class LeanbackVideoPlayer(
private val coroutineScope: CoroutineScope,
Expand Down Expand Up @@ -75,7 +75,7 @@ abstract class LeanbackVideoPlayer(
onPreparedListeners.forEach { it() }
loadTimeoutJob?.cancel()
loadTimeoutJob = coroutineScope.launch {
delay(SP.videoPlayerLoadTimeout)
delay(Settings.videoPlayerLoadTimeout)
triggerError(PlaybackException.LOAD_TIMEOUT)
}
cutoffTimeoutJob?.cancel()
Expand All @@ -90,7 +90,7 @@ abstract class LeanbackVideoPlayer(
if (currentPosition != newPosition) {
cutoffTimeoutJob?.cancel()
cutoffTimeoutJob = coroutineScope.launch {
delay(SP.videoPlayerLoadTimeout)
delay(Settings.videoPlayerLoadTimeout)
onCutoffListeners.forEach { it() }
}
}
Expand Down
Loading

0 comments on commit a6d6d8c

Please sign in to comment.