mirror of
https://github.com/lizongying/my-tv.git
synced 2026-10-28 23:26:29 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d65ac508eb | ||
|
|
b372d52510 | ||
|
|
608a7e3fef | ||
|
|
b980729224 | ||
|
|
641f8a9108 | ||
|
|
74b62870c6 | ||
|
|
a3a9bdc762 | ||
|
|
019c5a8e66 | ||
|
|
fd897f68c0 | ||
|
|
65c4b0cf52 | ||
|
|
8290a86909 | ||
|
|
4e05fe91d7 | ||
|
|
d5de8a8d2a | ||
|
|
c232099d29 | ||
|
|
3fb4b1e585 | ||
|
|
7b0e144cb1 | ||
|
|
06b8df5f82 | ||
|
|
7bed18ee6d | ||
|
|
0c2beb936a | ||
|
|
51ab79b5ca | ||
|
|
c8de039d05 | ||
|
|
c9494f7bf3 | ||
|
|
79b6cfcd11 | ||
|
|
31988d0d86 | ||
|
|
e55e8ceb18 | ||
|
|
0b62742350 | ||
|
|
558fe7e4e7 | ||
|
|
e2145f8d0d | ||
|
|
46b4df1306 | ||
|
|
358539f9c3 | ||
|
|
17d8d4cb46 | ||
|
|
dc81112a3d | ||
|
|
95ea83e45c | ||
|
|
a6078e75e1 | ||
|
|
8a3720049f | ||
|
|
ede420a190 | ||
|
|
f94d136a03 | ||
|
|
e7780434d7 | ||
|
|
67edb2830c | ||
|
|
2869164368 | ||
|
|
83a70291d4 | ||
|
|
872f668c59 | ||
|
|
426839c747 | ||
|
|
3e513d5adf | ||
|
|
86d4081d03 | ||
|
|
f76aa37169 | ||
|
|
d944777fc6 | ||
|
|
a45244c552 | ||
|
|
809ec920a5 | ||
|
|
8e4f7df8d4 | ||
|
|
fe209183ea | ||
|
|
b7ec58ac5b | ||
|
|
096acdf55e | ||
|
|
c8d59d5aab | ||
|
|
2b4b823946 | ||
|
|
127ceeb0b0 | ||
|
|
9dd6a2155f | ||
|
|
526a7c5c40 | ||
|
|
960f890ddd | ||
|
|
0a7837c577 | ||
|
|
d8342e8c6a | ||
|
|
6387f48409 | ||
|
|
807300918c | ||
|
|
36eacb7a57 | ||
|
|
b4abe0ccc6 | ||
|
|
fd1dc8d3c7 | ||
|
|
ea56bf1b80 | ||
|
|
4fb27ba502 | ||
|
|
a746fe6c65 | ||
|
|
594d5e3499 | ||
|
|
6061187bc8 | ||
|
|
cd8b37e63c | ||
|
|
aa3ba1d41f | ||
|
|
c778ac07ba | ||
|
|
700c8b4c04 | ||
|
|
825a872a09 | ||
|
|
54b43664ec | ||
|
|
a93cfb455c | ||
|
|
8535689e95 | ||
|
|
1714633cb7 | ||
|
|
f7b024f6da | ||
|
|
dd8df63b01 | ||
|
|
a4c95efd71 | ||
|
|
9f32fa3673 | ||
|
|
b3d0093ab0 | ||
|
|
5798d3a5fe | ||
|
|
4eb90de79d | ||
|
|
b8232971e2 | ||
|
|
bc3681b0a6 | ||
|
|
088808c3fd | ||
|
|
73239a6677 | ||
|
|
cc2514a81a | ||
|
|
bcf9bab25f | ||
|
|
f7eebb3f7a | ||
|
|
0f4a33a3fc | ||
|
|
c17d62c698 | ||
|
|
33d3da97e5 | ||
|
|
ba95ce5374 | ||
|
|
e1ee909071 | ||
|
|
1fd0951f92 | ||
|
|
42b072f5ec | ||
|
|
a23b1e11ce | ||
|
|
1ac6d87c3c | ||
|
|
b075a7db81 |
@@ -1,13 +1,5 @@
|
|||||||
## 更新日誌
|
## 更新日誌
|
||||||
|
|
||||||
### v2.1.2
|
|
||||||
|
|
||||||
*
|
|
||||||
|
|
||||||
### v2.1.1
|
|
||||||
|
|
||||||
* 平衡聲音
|
|
||||||
|
|
||||||
### v2.1.0
|
### v2.1.0
|
||||||
|
|
||||||
* 恢復播放
|
* 恢復播放
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
* 音量不同
|
* 音量不同
|
||||||
* 大湾区卫视、广东4k超高清、广东珠江、三沙卫视、翡翠
|
* 大湾区卫视、广东4k超高清、广东珠江、三沙卫视
|
||||||
* CHC高清三个电影频道
|
* CHC高清三个电影频道
|
||||||
* 地方频道
|
* 地方频道
|
||||||
* 收藏夹
|
* 收藏夹
|
||||||
@@ -35,9 +35,18 @@
|
|||||||
* 亮度调节
|
* 亮度调节
|
||||||
* 音量调节
|
* 音量调节
|
||||||
* 軟解
|
* 軟解
|
||||||
|
* 自動更新
|
||||||
|
|
||||||
|
無法自啟的設備:
|
||||||
|
斐讯N1盒子,[Phicomm] Phicomm p230 (Android 7.1.2)
|
||||||
|
|
||||||
|
閃退:
|
||||||
|
中国移动盒子(新魔百和M302A) 4.4.2
|
||||||
|
|
||||||
## 版权说明
|
## 版权说明
|
||||||
|
|
||||||
|
[LICENSE](./LICENSE)
|
||||||
|
|
||||||
本项目仅供学习研究,禁止用于商业用途,请于下载二十四小时内删除。
|
本项目仅供学习研究,禁止用于商业用途,请于下载二十四小时内删除。
|
||||||
|
|
||||||
本项目可能随时终止,请大家谨慎使用,建议使用官方渠道进行观看。
|
本项目可能随时终止,请大家谨慎使用,建议使用官方渠道进行观看。
|
||||||
|
|||||||
@@ -4,4 +4,3 @@
|
|||||||
/CMakeFiles/
|
/CMakeFiles/
|
||||||
/Makefile
|
/Makefile
|
||||||
/src/main/cpp/native.c
|
/src/main/cpp/native.c
|
||||||
/src/main/cpp/aes.c
|
|
||||||
|
|||||||
+1
-3
@@ -21,9 +21,7 @@ if (IS_SO_BUILD)
|
|||||||
SHARED
|
SHARED
|
||||||
|
|
||||||
# Provides a relative path to your source file(s).
|
# Provides a relative path to your source file(s).
|
||||||
src/main/cpp/native.c
|
src/main/cpp/native.c)
|
||||||
src/main/cpp/aes.c
|
|
||||||
)
|
|
||||||
|
|
||||||
# 设置编译输出路径
|
# 设置编译输出路径
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
|
|||||||
+16
-55
@@ -13,7 +13,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.lizongying.mytv"
|
applicationId "com.lizongying.mytv"
|
||||||
minSdk 17
|
minSdk 21
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode VersionCode()
|
versionCode VersionCode()
|
||||||
versionName VersionName()
|
versionName VersionName()
|
||||||
@@ -26,7 +26,6 @@ android {
|
|||||||
cmake {
|
cmake {
|
||||||
arguments "-DIS_SO_BUILD=${project.hasProperty('IS_SO_BUILD') ? project.IS_SO_BUILD : true}"
|
arguments "-DIS_SO_BUILD=${project.hasProperty('IS_SO_BUILD') ? project.IS_SO_BUILD : true}"
|
||||||
|
|
||||||
// abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
|
||||||
abiFilters "armeabi-v7a", "arm64-v8a"
|
abiFilters "armeabi-v7a", "arm64-v8a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,9 +77,10 @@ static def VersionCode() {
|
|||||||
def replace = [v: "", ".": " ", "-": " "]
|
def replace = [v: "", ".": " ", "-": " "]
|
||||||
def arr = (process.text.trim().replace(replace) + " 0").split(" ")
|
def arr = (process.text.trim().replace(replace) + " 0").split(" ")
|
||||||
def versionCode = arr[0].toInteger() * 16777216 + arr[1].toInteger() * 65536 + arr[2].toInteger() * 256 + arr[3].toInteger()
|
def versionCode = arr[0].toInteger() * 16777216 + arr[1].toInteger() * 65536 + arr[2].toInteger() * 256 + arr[3].toInteger()
|
||||||
|
println("VersionCode $versionCode")
|
||||||
return versionCode
|
return versionCode
|
||||||
} catch (ignored) {
|
} catch (ignored) {
|
||||||
return 1
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,81 +88,42 @@ static def VersionName() {
|
|||||||
try {
|
try {
|
||||||
def process = "git describe --tags --always".execute()
|
def process = "git describe --tags --always".execute()
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
def versionName = process.text.trim() - "v"
|
return process.text.trim() - "v"
|
||||||
if (versionName.isEmpty()) {
|
|
||||||
versionName = "1.0.0"
|
|
||||||
}
|
|
||||||
return versionName
|
|
||||||
} catch (ignored) {
|
} catch (ignored) {
|
||||||
return "1.0.0"
|
return "1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def gson_version = "2.10.1"
|
|
||||||
def failureaccess_version = "1.0.2"
|
|
||||||
def guava_version = "33.2.1-android"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
def media3_version = "1.3.1"
|
||||||
// minSdk17
|
|
||||||
def media3_version = "1.2.1"
|
|
||||||
|
|
||||||
implementation "androidx.media3:media3-ui:$media3_version"
|
implementation "androidx.media3:media3-ui:$media3_version"
|
||||||
|
|
||||||
// For media playback using ExoPlayer
|
// For media playback using ExoPlayer
|
||||||
implementation("com.google.guava:failureaccess:$failureaccess_version")
|
implementation "androidx.media3:media3-exoplayer:$media3_version"
|
||||||
implementation("com.google.guava:guava:$guava_version")
|
|
||||||
implementation("androidx.media3:media3-common:$media3_version") {
|
|
||||||
exclude group: 'com.google.guava', module: 'guava'
|
|
||||||
exclude group: 'com.google.guava', module: 'failureaccess'
|
|
||||||
}
|
|
||||||
implementation("androidx.media3:media3-exoplayer:$media3_version")
|
|
||||||
|
|
||||||
// For HLS playback support with ExoPlayer
|
// For HLS playback support with ExoPlayer
|
||||||
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
||||||
|
|
||||||
// 21:2.9.0 17:2.6.4
|
// 21:2.11.0 17:2.6.4
|
||||||
def retrofit2_version = "2.6.4"
|
def retrofit2_version = "2.11.0"
|
||||||
|
|
||||||
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
||||||
// Gson 2.10.1 and older: API level 19
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
|
||||||
implementation("com.google.code.gson:gson:$gson_version")
|
|
||||||
implementation("com.squareup.retrofit2:converter-gson:$retrofit2_version") {
|
|
||||||
exclude group: 'com.google.code.gson', module: 'gson'
|
|
||||||
}
|
|
||||||
implementation "com.squareup.retrofit2:converter-protobuf:$retrofit2_version"
|
implementation "com.squareup.retrofit2:converter-protobuf:$retrofit2_version"
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
|
||||||
|
|
||||||
|
implementation 'androidx.leanback:leanback:1.2.0-alpha04'
|
||||||
|
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
|
|
||||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
implementation 'androidx.core:core-ktx:1.13.0'
|
||||||
implementation 'androidx.core:core-ktx:1.11.0-beta02'
|
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0"
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
|
||||||
implementation 'androidx.leanback:leanback:1.2.0-alpha02'
|
|
||||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
|
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC")
|
||||||
|
|
||||||
implementation 'javax.annotation:javax.annotation-api:1.3.2'
|
implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3'
|
||||||
}
|
implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3'
|
||||||
|
implementation 'com.google.android.exoplayer:exoplayer-hls:2.13.3'
|
||||||
configurations.configureEach {
|
|
||||||
resolutionStrategy {
|
|
||||||
force("com.google.code.gson:gson:$gson_version")
|
|
||||||
force "com.google.guava:failureaccess:$failureaccess_version"
|
|
||||||
force "com.google.guava:guava:$guava_version"
|
|
||||||
eachDependency { details ->
|
|
||||||
if (details.requested.group == 'com.google.code.gson') {
|
|
||||||
details.useVersion "$gson_version"
|
|
||||||
}
|
|
||||||
if (details.requested.group == 'com.google.guava' && details.requested.name == 'failureaccess') {
|
|
||||||
details.useVersion "$failureaccess_version"
|
|
||||||
}
|
|
||||||
if (details.requested.group == 'com.google.guava' && details.requested.name == 'guava') {
|
|
||||||
details.useVersion "$guava_version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Vendored
+1
-7
@@ -18,10 +18,4 @@
|
|||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
-keep class com.google.gson.** { *; }
|
|
||||||
-dontwarn com.google.gson.**
|
|
||||||
|
|
||||||
-keep class com.google.guava.** { *; }
|
|
||||||
-dontwarn com.google.guava.**
|
|
||||||
@@ -10,13 +10,11 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MyTVApplication"
|
android:name=".MyApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:banner="@drawable/banner"
|
android:banner="@drawable/banner"
|
||||||
android:icon="@drawable/logo"
|
android:icon="@drawable/logo"
|
||||||
@@ -38,9 +36,6 @@
|
|||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data
|
|
||||||
android:name="android.windowLayoutInDisplayCutoutMode"
|
|
||||||
android:value="shortEdges" />
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
@@ -63,16 +58,5 @@
|
|||||||
android:name=".InitializerProvider"
|
android:name=".InitializerProvider"
|
||||||
android:authorities="${applicationId}.InitializerProvider"
|
android:authorities="${applicationId}.InitializerProvider"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.5" />
|
|
||||||
<provider
|
|
||||||
android:name="androidx.core.content.FileProvider"
|
|
||||||
android:authorities="${applicationId}.provider"
|
|
||||||
android:exported="false"
|
|
||||||
android:grantUriPermissions="true">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/file_paths" />
|
|
||||||
</provider>
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
|
|||||||
#ifndef AES_H
|
|
||||||
#define AES_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void encode(const char *in, size_t size, char *out);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,217 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewConfiguration
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.animation.ScaleAnimation
|
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.core.view.setPadding
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.lizongying.mytv.databinding.CardBinding
|
|
||||||
import com.lizongying.mytv.models.TVListViewModel
|
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
|
|
||||||
class CardAdapter(
|
|
||||||
private val recyclerView: RecyclerView,
|
|
||||||
private val mainFragment: MainFragment,
|
|
||||||
private var tvListViewModel: TVListViewModel,
|
|
||||||
) :
|
|
||||||
RecyclerView.Adapter<CardAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
private var listener: ItemListener? = null
|
|
||||||
private var focused: View? = null
|
|
||||||
|
|
||||||
var focusable = false
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
|
||||||
val binding = CardBinding.inflate(inflater, parent, false)
|
|
||||||
|
|
||||||
val application = mainFragment.requireActivity().applicationContext as MyTVApplication
|
|
||||||
|
|
||||||
binding.card.layoutParams.width = application.px2Px(binding.card.layoutParams.width)
|
|
||||||
binding.card.layoutParams.height = application.px2Px(binding.card.layoutParams.height)
|
|
||||||
binding.icon.layoutParams.height = application.px2Px(binding.icon.layoutParams.height)
|
|
||||||
binding.icon.setPadding(application.px2Px(binding.icon.paddingTop))
|
|
||||||
binding.main.layoutParams.height = application.px2Px(binding.main.layoutParams.height)
|
|
||||||
binding.main.setPadding(application.px2Px(binding.main.paddingTop))
|
|
||||||
binding.title.textSize = application.px2PxFont(binding.title.textSize)
|
|
||||||
binding.desc.textSize = application.px2PxFont(binding.desc.textSize)
|
|
||||||
val layoutParams = binding.desc.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParams.topMargin = application.px2Px(binding.desc.marginTop)
|
|
||||||
binding.desc.layoutParams = layoutParams
|
|
||||||
|
|
||||||
val cardView = binding.root
|
|
||||||
cardView.isClickable = true
|
|
||||||
cardView.isFocusable = true
|
|
||||||
cardView.isFocusableInTouchMode = true
|
|
||||||
return ViewHolder(cardView, binding)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clear() {
|
|
||||||
focused?.clearFocus()
|
|
||||||
recyclerView.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startScaleAnimation(view: View) {
|
|
||||||
val scaleAnimation = ScaleAnimation(
|
|
||||||
0.9f, 1.0f,
|
|
||||||
0.9f, 1.0f,
|
|
||||||
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
|
|
||||||
ScaleAnimation.RELATIVE_TO_SELF, 0.5f
|
|
||||||
)
|
|
||||||
scaleAnimation.duration = 200
|
|
||||||
scaleAnimation.fillAfter = false
|
|
||||||
view.startAnimation(scaleAnimation)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
|
||||||
val item = tvListViewModel.getTVViewModel(position)
|
|
||||||
|
|
||||||
val tvViewModel = item as TVViewModel
|
|
||||||
val cardView = viewHolder.view
|
|
||||||
cardView.tag = tvViewModel
|
|
||||||
|
|
||||||
val onFocusChangeListener = View.OnFocusChangeListener { view, hasFocus ->
|
|
||||||
if (hasFocus) {
|
|
||||||
listener?.onItemHasFocus(item)
|
|
||||||
focused = cardView
|
|
||||||
|
|
||||||
if (focusable) {
|
|
||||||
startScaleAnimation(cardView)
|
|
||||||
viewHolder.focus(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewHolder.focus(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.onFocusChangeListener = onFocusChangeListener
|
|
||||||
|
|
||||||
cardView.setOnClickListener { _ ->
|
|
||||||
listener?.onItemClicked(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
var downX = 0f
|
|
||||||
var downY = 0f
|
|
||||||
val touchSlop = ViewConfiguration.get(cardView.context).scaledTouchSlop
|
|
||||||
|
|
||||||
cardView.setOnTouchListener { _, event ->
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
downX = event.x
|
|
||||||
downY = event.y
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
val upX = event.x
|
|
||||||
val upY = event.y
|
|
||||||
val deltaX = abs(upX - downX)
|
|
||||||
val deltaY = abs(upY - downY)
|
|
||||||
if (deltaX < touchSlop && deltaY < touchSlop) {
|
|
||||||
// 如果位移量小于阈值,则执行点击操作
|
|
||||||
cardView.performClick()
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.setOnKeyListener { _, keyCode, event: KeyEvent? ->
|
|
||||||
if (event?.action == KeyEvent.ACTION_DOWN) {
|
|
||||||
return@setOnKeyListener listener?.onKey(keyCode) ?: false
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
viewHolder.binding.title.text = tvViewModel.getTV().title
|
|
||||||
|
|
||||||
viewHolder.binding.icon.let {
|
|
||||||
Glide.with(viewHolder.view.context)
|
|
||||||
.load(tvViewModel.getTV().logo)
|
|
||||||
.centerInside()
|
|
||||||
.into(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
|
|
||||||
if (!epg.isNullOrEmpty()) {
|
|
||||||
viewHolder.binding.desc.text = epg.last().title
|
|
||||||
} else {
|
|
||||||
viewHolder.binding.desc.text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount() = tvListViewModel.size()
|
|
||||||
|
|
||||||
class ViewHolder(itemView: View, var binding: CardBinding) : RecyclerView.ViewHolder(itemView) {
|
|
||||||
val view = itemView
|
|
||||||
|
|
||||||
fun focus(hasFocus: Boolean) {
|
|
||||||
if (hasFocus) {
|
|
||||||
binding.main.setBackgroundResource(R.drawable.rounded_light_bottom)
|
|
||||||
} else {
|
|
||||||
binding.main.setBackgroundResource(R.drawable.rounded_dark_bottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateEPG() {
|
|
||||||
for (i in 0 until recyclerView.childCount) {
|
|
||||||
val childView = recyclerView.getChildAt(i)
|
|
||||||
|
|
||||||
val viewHolder = recyclerView.getChildViewHolder(childView) as ViewHolder
|
|
||||||
|
|
||||||
if (viewHolder.view.tag != null && viewHolder.view.tag is TVViewModel) {
|
|
||||||
val tvViewModel = viewHolder.view.tag as TVViewModel
|
|
||||||
|
|
||||||
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
|
|
||||||
|
|
||||||
if (!epg.isNullOrEmpty()) {
|
|
||||||
val title = epg.last().title
|
|
||||||
if (viewHolder.binding.desc.text != title) {
|
|
||||||
viewHolder.binding.desc.text = title
|
|
||||||
Log.i(TAG, "updateEPG $title")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (viewHolder.binding.desc.text != "") {
|
|
||||||
viewHolder.binding.desc.text = ""
|
|
||||||
Log.i(TAG, "updateEPG")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toPosition(position: Int) {
|
|
||||||
recyclerView.post {
|
|
||||||
recyclerView.scrollToPosition(position)
|
|
||||||
recyclerView.getChildAt(position)?.isSelected
|
|
||||||
recyclerView.getChildAt(position)?.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ItemListener {
|
|
||||||
fun onItemHasFocus(tvViewModel: TVViewModel)
|
|
||||||
fun onItemClicked(tvViewModel: TVViewModel)
|
|
||||||
fun onKey(keyCode: Int): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setItemListener(listener: ItemListener) {
|
|
||||||
this.listener = listener
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "CardAdapter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.lizongying.mytv
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.ContextThemeWrapper
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.leanback.widget.ImageCardView
|
||||||
|
import androidx.leanback.widget.Presenter
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
|
|
||||||
|
class CardPresenter(
|
||||||
|
private val context: Context,
|
||||||
|
) : Presenter() {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup): ViewHolder {
|
||||||
|
val cardView = object :
|
||||||
|
ImageCardView(ContextThemeWrapper(parent.context, R.style.CustomImageCardTheme)) {}
|
||||||
|
|
||||||
|
cardView.isFocusable = true
|
||||||
|
cardView.isFocusableInTouchMode = true
|
||||||
|
return ViewHolder(cardView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(viewHolder: ViewHolder, item: Any?) {
|
||||||
|
val tvViewModel = item as TVViewModel
|
||||||
|
val cardView = viewHolder.view as ImageCardView
|
||||||
|
|
||||||
|
cardView.titleText = tvViewModel.getTV().title
|
||||||
|
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT)
|
||||||
|
cardView.tag = tvViewModel.videoUrl.value
|
||||||
|
|
||||||
|
cardView.mainImageView?.let {
|
||||||
|
Glide.with(viewHolder.view.context)
|
||||||
|
.load(tvViewModel.getTV().logo)
|
||||||
|
.centerInside()
|
||||||
|
.into(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
cardView.setBackgroundColor(Color.WHITE)
|
||||||
|
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
||||||
|
|
||||||
|
// cardView.setOnFocusChangeListener { v, hasFocus ->
|
||||||
|
// run {
|
||||||
|
// if (hasFocus) {
|
||||||
|
// if (v != null) {
|
||||||
|
// (v as ImageCardView).setInfoAreaBackgroundColor(context.resources.getColor(R.color.focus))
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (v != null) {
|
||||||
|
// (v as ImageCardView).setInfoAreaBackgroundColor(context.resources.getColor(R.color.ic_launcher_background))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
|
||||||
|
if (!epg.isNullOrEmpty()) {
|
||||||
|
cardView.contentText = epg.last().title
|
||||||
|
} else {
|
||||||
|
cardView.contentText = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnbindViewHolder(viewHolder: ViewHolder) {
|
||||||
|
val cardView = viewHolder.view as ImageCardView
|
||||||
|
cardView.mainImage = null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "CardPresenter"
|
||||||
|
private const val CARD_WIDTH = 300
|
||||||
|
private const val CARD_HEIGHT = 101
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.marginEnd
|
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.lizongying.mytv.databinding.ChannelBinding
|
import com.lizongying.mytv.databinding.ChannelBinding
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
@@ -17,7 +15,7 @@ class ChannelFragment : Fragment() {
|
|||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private val delay: Long = 5000
|
private val delay: Long = 3000
|
||||||
private var channel = 0
|
private var channel = 0
|
||||||
private var channelCount = 0
|
private var channelCount = 0
|
||||||
|
|
||||||
@@ -28,30 +26,45 @@ class ChannelFragment : Fragment() {
|
|||||||
_binding = ChannelBinding.inflate(inflater, container, false)
|
_binding = ChannelBinding.inflate(inflater, container, false)
|
||||||
_binding!!.root.visibility = View.GONE
|
_binding!!.root.visibility = View.GONE
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
val activity = requireActivity()
|
||||||
|
val application = activity.applicationContext as MyApplication
|
||||||
|
val displayMetrics = application.getDisplayMetrics()
|
||||||
|
|
||||||
binding.channel.layoutParams.width = application.px2Px(binding.channel.layoutParams.width)
|
displayMetrics.density
|
||||||
binding.channel.layoutParams.height = application.px2Px(binding.channel.layoutParams.height)
|
|
||||||
|
|
||||||
val layoutParams = binding.channel.layoutParams as ViewGroup.MarginLayoutParams
|
var screenWidth = displayMetrics.widthPixels
|
||||||
layoutParams.topMargin = application.px2Px(binding.channel.marginTop)
|
var screenHeight = displayMetrics.heightPixels
|
||||||
layoutParams.marginEnd = application.px2Px(binding.channel.marginEnd)
|
if (screenHeight > screenWidth) {
|
||||||
binding.channel.layoutParams = layoutParams
|
screenWidth = displayMetrics.heightPixels
|
||||||
|
screenHeight = displayMetrics.widthPixels
|
||||||
|
}
|
||||||
|
|
||||||
binding.content.textSize = application.px2PxFont(binding.content.textSize)
|
val ratio = 16f / 9f
|
||||||
binding.time.textSize = application.px2PxFont(binding.time.textSize)
|
|
||||||
|
|
||||||
binding.main.layoutParams.width = application.shouldWidthPx()
|
if (screenWidth / screenHeight > ratio) {
|
||||||
binding.main.layoutParams.height = application.shouldHeightPx()
|
val x = ((screenWidth - screenHeight * ratio) / 2).toInt()
|
||||||
|
val originalLayoutParams =
|
||||||
|
binding.channelFragment.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
originalLayoutParams.rightMargin += x
|
||||||
|
binding.channelFragment.layoutParams = originalLayoutParams
|
||||||
|
}
|
||||||
|
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
if (screenWidth / screenHeight < ratio) {
|
||||||
|
val y = ((screenHeight - screenWidth / ratio) / 2).toInt()
|
||||||
|
val originalLayoutParams =
|
||||||
|
binding.channelFragment.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
originalLayoutParams.topMargin += y
|
||||||
|
binding.channelFragment.layoutParams = originalLayoutParams
|
||||||
|
}
|
||||||
|
|
||||||
|
(activity as MainActivity).fragmentReady("ChannelFragment")
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(tvViewModel: TVViewModel) {
|
fun show(tvViewModel: TVViewModel) {
|
||||||
handler.removeCallbacks(hideRunnable)
|
handler.removeCallbacks(hideRunnable)
|
||||||
handler.removeCallbacks(playRunnable)
|
handler.removeCallbacks(playRunnable)
|
||||||
binding.content.text = (tvViewModel.getTV().id.plus(1)).toString()
|
binding.channelContent.text = (tvViewModel.getTV().id.plus(1)).toString()
|
||||||
view?.visibility = View.VISIBLE
|
view?.visibility = View.VISIBLE
|
||||||
handler.postDelayed(hideRunnable, delay)
|
handler.postDelayed(hideRunnable, delay)
|
||||||
}
|
}
|
||||||
@@ -61,11 +74,13 @@ class ChannelFragment : Fragment() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
channelCount++
|
channelCount++
|
||||||
|
Log.i(TAG, "channelCount ${channelCount}")
|
||||||
this.channel = "${this.channel}$channel".toInt()
|
this.channel = "${this.channel}$channel".toInt()
|
||||||
|
Log.i(TAG, "this.channel ${this.channel}")
|
||||||
handler.removeCallbacks(hideRunnable)
|
handler.removeCallbacks(hideRunnable)
|
||||||
handler.removeCallbacks(playRunnable)
|
handler.removeCallbacks(playRunnable)
|
||||||
if (channelCount < 2) {
|
if (channelCount < 2) {
|
||||||
binding.content.text = "${this.channel}"
|
binding.channelContent.text = "${this.channel}"
|
||||||
view?.visibility = View.VISIBLE
|
view?.visibility = View.VISIBLE
|
||||||
handler.postDelayed(playRunnable, delay)
|
handler.postDelayed(playRunnable, delay)
|
||||||
} else {
|
} else {
|
||||||
@@ -87,18 +102,20 @@ class ChannelFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val hideRunnable = Runnable {
|
private val hideRunnable = Runnable {
|
||||||
binding.content.text = ""
|
binding.channelContent.text = ""
|
||||||
view?.visibility = View.GONE
|
view?.visibility = View.GONE
|
||||||
channel = 0
|
channel = 0
|
||||||
channelCount = 0
|
channelCount = 0
|
||||||
|
Log.i(TAG, "hideRunnable")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val playRunnable = Runnable {
|
private val playRunnable = Runnable {
|
||||||
(activity as MainActivity).play(channel - 1)
|
(activity as MainActivity).play(channel - 1)
|
||||||
binding.content.text = ""
|
binding.channelContent.text = ""
|
||||||
view?.visibility = View.GONE
|
view?.visibility = View.GONE
|
||||||
channel = 0
|
channel = 0
|
||||||
channelCount = 0
|
channelCount = 0
|
||||||
|
Log.i(TAG, "playRunnable")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
|||||||
@@ -3,61 +3,28 @@ package com.lizongying.mytv
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.lizongying.mytv.databinding.ConfirmationBinding
|
|
||||||
|
|
||||||
class ConfirmationFragment(
|
class ConfirmationFragment(
|
||||||
private val listener: ConfirmationListener,
|
private val listener: ConfirmationListener,
|
||||||
private val message: String,
|
private val message: String
|
||||||
private val update: Boolean
|
|
||||||
) : DialogFragment() {
|
) : DialogFragment() {
|
||||||
//
|
|
||||||
// private var _binding: ConfirmationBinding? = null
|
|
||||||
// private val binding get() = _binding!!
|
|
||||||
//
|
|
||||||
// override fun onCreateView(
|
|
||||||
// inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
// savedInstanceState: Bundle?
|
|
||||||
// ): View {
|
|
||||||
// _binding = ConfirmationBinding.inflate(inflater, container, false)
|
|
||||||
// return binding.root
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun updateProgress(progress: Int) {
|
|
||||||
// binding.progressBar.progress = progress
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onDestroyView() {
|
|
||||||
// super.onDestroyView()
|
|
||||||
// _binding = null
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
return activity?.let {
|
return activity?.let {
|
||||||
val builder = AlertDialog.Builder(it)
|
val builder = AlertDialog.Builder(it)
|
||||||
builder.setTitle(message)
|
builder.setTitle("确定更新吗?")
|
||||||
if (update) {
|
.setMessage(message)
|
||||||
builder.setMessage("确定更新吗?")
|
.setPositiveButton(
|
||||||
.setPositiveButton(
|
"确定"
|
||||||
"确定"
|
) { _, _ ->
|
||||||
) { _, _ ->
|
listener.onConfirm()
|
||||||
listener.onConfirm()
|
}
|
||||||
}
|
.setNegativeButton(
|
||||||
.setNegativeButton(
|
"取消"
|
||||||
"取消"
|
) { _, _ ->
|
||||||
) { _, _ ->
|
listener.onCancel()
|
||||||
listener.onCancel()
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
builder.setMessage("")
|
|
||||||
.setNegativeButton(
|
|
||||||
"好的"
|
|
||||||
) { _, _ ->
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.create()
|
builder.create()
|
||||||
} ?: throw IllegalStateException("Activity cannot be null")
|
} ?: throw IllegalStateException("Activity cannot be null")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.lizongying.mytv.api
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
||||||
@@ -7,8 +7,6 @@ class Encryptor {
|
|||||||
|
|
||||||
external fun encrypt(t: String, e: String, r: String, n: String, i: String): String
|
external fun encrypt(t: String, e: String, r: String, n: String, i: String): String
|
||||||
|
|
||||||
external fun encrypt2(t: String): String
|
|
||||||
|
|
||||||
external fun hash(data: ByteArray): ByteArray?
|
external fun hash(data: ByteArray): ByteArray?
|
||||||
|
|
||||||
external fun hash2(data: ByteArray): ByteArray?
|
external fun hash2(data: ByteArray): ByteArray?
|
||||||
@@ -1,49 +1,28 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.marginStart
|
import androidx.leanback.app.ErrorSupportFragment
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import com.lizongying.mytv.databinding.ErrorBinding
|
|
||||||
|
|
||||||
class ErrorFragment : Fragment() {
|
class ErrorFragment : ErrorSupportFragment() {
|
||||||
private var _binding: ErrorBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
override fun onCreateView(
|
internal fun setErrorContent(message: String) {
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
imageDrawable =
|
||||||
savedInstanceState: Bundle?
|
ContextCompat.getDrawable(context!!, androidx.leanback.R.drawable.lb_ic_sad_cloud)
|
||||||
): View {
|
this.message = message
|
||||||
_binding = ErrorBinding.inflate(inflater, container, false)
|
setDefaultBackground(TRANSLUCENT)
|
||||||
|
backgroundDrawable = ContextCompat.getDrawable(
|
||||||
|
context!!,
|
||||||
|
R.color.black
|
||||||
|
)
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
buttonText = resources.getString(R.string.dismiss_error)
|
||||||
|
buttonClickListener = View.OnClickListener {
|
||||||
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
|
fragmentManager!!.beginTransaction().remove(this@ErrorFragment).commit()
|
||||||
binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height)
|
}
|
||||||
|
|
||||||
val layoutParams = binding.msg.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParams.topMargin = application.px2Px(binding.msg.marginTop)
|
|
||||||
binding.msg.layoutParams = layoutParams
|
|
||||||
|
|
||||||
binding.msg.textSize = application.px2PxFont(binding.msg.textSize)
|
|
||||||
|
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
fun show(msg: String) {
|
|
||||||
binding.msg.text = msg
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ErrorFragment"
|
private const val TRANSLUCENT = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.marginBottom
|
|
||||||
import androidx.core.view.marginStart
|
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.core.view.setPadding
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.lizongying.mytv.databinding.InfoBinding
|
import com.lizongying.mytv.databinding.InfoBinding
|
||||||
@@ -21,64 +16,31 @@ class InfoFragment : Fragment() {
|
|||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private val delay: Long = 5000
|
private val delay: Long = 3000
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = InfoBinding.inflate(inflater, container, false)
|
_binding = InfoBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
|
||||||
|
|
||||||
binding.info.layoutParams.width = application.px2Px(binding.info.layoutParams.width)
|
|
||||||
binding.info.layoutParams.height = application.px2Px(binding.info.layoutParams.height)
|
|
||||||
|
|
||||||
val layoutParams = binding.info.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParams.bottomMargin = application.px2Px(binding.info.marginBottom)
|
|
||||||
binding.info.layoutParams = layoutParams
|
|
||||||
|
|
||||||
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
|
|
||||||
binding.logo.setPadding(application.px2Px(binding.logo.paddingTop))
|
|
||||||
binding.main.layoutParams.width = application.px2Px(binding.main.layoutParams.width)
|
|
||||||
binding.main.setPadding(application.px2Px(binding.main.paddingTop))
|
|
||||||
|
|
||||||
val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsMain.marginStart = application.px2Px(binding.main.marginStart)
|
|
||||||
binding.main.layoutParams = layoutParamsMain
|
|
||||||
|
|
||||||
val layoutParamsDesc = binding.desc.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsDesc.topMargin = application.px2Px(binding.desc.marginTop)
|
|
||||||
binding.desc.layoutParams = layoutParamsDesc
|
|
||||||
|
|
||||||
binding.title.textSize = application.px2PxFont(binding.title.textSize)
|
|
||||||
binding.desc.textSize = application.px2PxFont(binding.desc.textSize)
|
|
||||||
|
|
||||||
binding.container.layoutParams.width = application.shouldWidthPx()
|
|
||||||
binding.container.layoutParams.height = application.shouldHeightPx()
|
|
||||||
|
|
||||||
_binding!!.root.visibility = View.GONE
|
_binding!!.root.visibility = View.GONE
|
||||||
|
(activity as MainActivity).fragmentReady("InfoFragment")
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(tvViewModel: TVViewModel) {
|
fun show(tvViewModel: TVViewModel) {
|
||||||
if (_binding == null) {
|
binding.textView.text = tvViewModel.getTV().title
|
||||||
return
|
|
||||||
}
|
|
||||||
binding.title.text = tvViewModel.getTV().title
|
|
||||||
|
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(tvViewModel.getTV().logo)
|
.load(tvViewModel.getTV().logo)
|
||||||
.into(binding.logo)
|
.into(binding.infoLogo)
|
||||||
|
|
||||||
Log.i(TAG, "${tvViewModel.getTV().title} ${tvViewModel.epg.value}")
|
Log.i(TAG, "${tvViewModel.getTV().title} ${tvViewModel.epg.value}")
|
||||||
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
|
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
|
||||||
if (!epg.isNullOrEmpty()) {
|
if (!epg.isNullOrEmpty()) {
|
||||||
binding.desc.text = epg.last().title
|
binding.infoDesc.text = epg.last().title
|
||||||
} else {
|
} else {
|
||||||
binding.desc.text = ""
|
binding.infoDesc.text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.removeCallbacks(removeRunnable)
|
handler.removeCallbacks(removeRunnable)
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
|
|
||||||
class ItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
|
||||||
|
|
||||||
private var application: MyTVApplication
|
|
||||||
|
|
||||||
init {
|
|
||||||
application = context.applicationContext as MyTVApplication
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemOffsets(
|
|
||||||
outRect: Rect,
|
|
||||||
view: View,
|
|
||||||
parent: RecyclerView,
|
|
||||||
state: RecyclerView.State
|
|
||||||
) {
|
|
||||||
super.getItemOffsets(outRect, view, parent, state)
|
|
||||||
val space = application.dp2Px(5)
|
|
||||||
outRect.top = space
|
|
||||||
outRect.bottom = space
|
|
||||||
outRect.left = space
|
|
||||||
outRect.right = space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import com.lizongying.mytv.databinding.LoadingBinding
|
|
||||||
|
|
||||||
class LoadingFragment : Fragment() {
|
|
||||||
private var _binding: LoadingBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
_binding = LoadingBinding.inflate(inflater, container, false)
|
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
|
||||||
|
|
||||||
binding.bar.layoutParams.width = application.px2Px(binding.bar.layoutParams.width)
|
|
||||||
binding.bar.layoutParams.height = application.px2Px(binding.bar.layoutParams.height)
|
|
||||||
|
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "LoadingFragment"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@@ -9,35 +12,28 @@ import android.view.GestureDetector
|
|||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
||||||
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
import android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
||||||
import android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
import com.lizongying.mytv.requests.Request
|
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPreferenceChangeListener {
|
class MainActivity : FragmentActivity(), Request.RequestListener {
|
||||||
|
|
||||||
private var ready = 0
|
private var ready = 0
|
||||||
private val playerFragment = PlayerFragment()
|
private val playerFragment = PlayerFragment()
|
||||||
private val errorFragment = ErrorFragment()
|
|
||||||
|
|
||||||
private val loadingFragment = LoadingFragment()
|
|
||||||
private val mainFragment = MainFragment()
|
private val mainFragment = MainFragment()
|
||||||
private val infoFragment = InfoFragment()
|
private val infoFragment = InfoFragment()
|
||||||
private val channelFragment = ChannelFragment()
|
private val channelFragment = ChannelFragment()
|
||||||
private var timeFragment = TimeFragment()
|
private var timeFragment = TimeFragment()
|
||||||
private val settingFragment = SettingFragment()
|
private val settingFragment = SettingFragment()
|
||||||
|
private val errorFragment = ErrorFragment()
|
||||||
|
|
||||||
private var doubleBackToExitPressedOnce = false
|
private var doubleBackToExitPressedOnce = false
|
||||||
|
|
||||||
@@ -45,98 +41,67 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
|
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private val delayHideMain: Long = 10000
|
private val delayHideMain: Long = 10000
|
||||||
private val delayHideSetting: Long = 15000
|
private val delayHideSetting: Long = 10000
|
||||||
|
|
||||||
init {
|
init {
|
||||||
Utils.setRequestListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun syncTime() {
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
|
val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
|
||||||
|
|
||||||
utilsJob.start()
|
utilsJob.start()
|
||||||
|
|
||||||
|
// utilsJob.await()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
Log.i(TAG, "onCreate")
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
val lp = window.attributes
|
|
||||||
lp.layoutInDisplayCutoutMode =
|
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
|
||||||
window.setAttributes(lp)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
window.decorView.apply {
|
|
||||||
systemUiVisibility =
|
|
||||||
SYSTEM_UI_FLAG_FULLSCREEN or
|
|
||||||
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
|
||||||
SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
|
||||||
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
||||||
window.decorView.systemUiVisibility =
|
|
||||||
SYSTEM_UI_FLAG_FULLSCREEN or
|
|
||||||
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
|
||||||
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
||||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
|
||||||
// window.statusBarColor = Color.TRANSPARENT
|
|
||||||
// window.navigationBarColor = Color.TRANSPARENT
|
|
||||||
// }
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
Request.setRequestListener(this)
|
Request.setRequestListener(this)
|
||||||
|
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||||
|
window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
val transaction = supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.add(R.id.main_browse_fragment, playerFragment)
|
.add(R.id.main_browse_fragment, playerFragment)
|
||||||
.add(R.id.main_browse_fragment, errorFragment)
|
|
||||||
// .add(R.id.main_browse_fragment, loadingFragment)
|
|
||||||
.add(R.id.main_browse_fragment, timeFragment)
|
.add(R.id.main_browse_fragment, timeFragment)
|
||||||
.add(R.id.main_browse_fragment, infoFragment)
|
.add(R.id.main_browse_fragment, infoFragment)
|
||||||
.add(R.id.main_browse_fragment, channelFragment)
|
.add(R.id.main_browse_fragment, channelFragment)
|
||||||
.add(R.id.main_browse_fragment, mainFragment)
|
.add(R.id.main_browse_fragment, mainFragment)
|
||||||
.hide(mainFragment)
|
.hide(mainFragment)
|
||||||
.hide(errorFragment)
|
.commit()
|
||||||
|
|
||||||
if (!SP.time) {
|
|
||||||
transaction.hide(timeFragment)
|
|
||||||
} else {
|
|
||||||
transaction.show(timeFragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.commitNow()
|
|
||||||
}
|
}
|
||||||
gestureDetector = GestureDetector(this, GestureListener())
|
gestureDetector = GestureDetector(this, GestureListener())
|
||||||
|
|
||||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
errorFragment.buttonClickListener = View.OnClickListener {
|
||||||
// val connectivityManager =
|
supportFragmentManager.beginTransaction()
|
||||||
// getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
.remove(errorFragment)
|
||||||
// connectivityManager.registerDefaultNetworkCallback(object :
|
.commit()
|
||||||
// ConnectivityManager.NetworkCallback() {
|
}
|
||||||
// override fun onAvailable(network: Network) {
|
|
||||||
// super.onAvailable(network)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
// Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
|
val connectivityManager =
|
||||||
// if (this@MainActivity.isNetworkConnected) {
|
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
// Log.i(TAG, "net isNetworkConnected")
|
connectivityManager.registerDefaultNetworkCallback(object :
|
||||||
// ready++
|
ConnectivityManager.NetworkCallback() {
|
||||||
// }
|
override fun onAvailable(network: Network) {
|
||||||
// }
|
super.onAvailable(network)
|
||||||
// })
|
Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
|
||||||
// } else {
|
if (this@MainActivity.isNetworkConnected) {
|
||||||
// Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
|
Log.i(TAG, "net isNetworkConnected")
|
||||||
// ready++
|
ready++
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
|
||||||
|
ready++
|
||||||
|
}
|
||||||
|
|
||||||
SP.setOnSharedPreferenceChangeListener(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showInfoFragment(tvViewModel: TVViewModel) {
|
fun showInfoFragment(tvViewModel: TVViewModel) {
|
||||||
@@ -146,52 +111,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showErrorFragment(msg: String) {
|
|
||||||
errorFragment.show(msg)
|
|
||||||
if (errorFragment.isVisible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.show(errorFragment)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hideErrorFragment() {
|
|
||||||
errorFragment.show("")
|
|
||||||
if (!errorFragment.isVisible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.hide(errorFragment)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showLoadingFragment() {
|
|
||||||
showFragment(loadingFragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hideLoadingFragment() {
|
|
||||||
hideFragment(loadingFragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showPlayerFragment() {
|
|
||||||
if (playerFragment.isVisible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.show(playerFragment)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hidePlayerFragment() {
|
|
||||||
if (!playerFragment.isVisible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.hide(playerFragment)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showChannel(channel: String) {
|
private fun showChannel(channel: String) {
|
||||||
if (!mainFragment.isHidden) {
|
if (!mainFragment.isHidden) {
|
||||||
return
|
return
|
||||||
@@ -208,6 +127,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
|
|
||||||
fun play(tvViewModel: TVViewModel) {
|
fun play(tvViewModel: TVViewModel) {
|
||||||
playerFragment.play(tvViewModel)
|
playerFragment.play(tvViewModel)
|
||||||
|
mainFragment.view?.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun play(itemPosition: Int) {
|
fun play(itemPosition: Int) {
|
||||||
@@ -222,11 +142,18 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
mainFragment.next()
|
mainFragment.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun prevSource() {
|
||||||
|
// mainFragment.prevSource()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextSource() {
|
||||||
|
// mainFragment.nextSource()
|
||||||
|
}
|
||||||
|
|
||||||
fun switchMainFragment() {
|
fun switchMainFragment() {
|
||||||
val transaction = supportFragmentManager.beginTransaction()
|
val transaction = supportFragmentManager.beginTransaction()
|
||||||
|
|
||||||
if (mainFragment.isHidden) {
|
if (mainFragment.isHidden) {
|
||||||
mainFragment.setPosition()
|
|
||||||
transaction.show(mainFragment)
|
transaction.show(mainFragment)
|
||||||
mainActive()
|
mainActive()
|
||||||
} else {
|
} else {
|
||||||
@@ -244,6 +171,12 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
fun settingDelayHide() {
|
fun settingDelayHide() {
|
||||||
handler.removeCallbacks(hideSetting)
|
handler.removeCallbacks(hideSetting)
|
||||||
handler.postDelayed(hideSetting, delayHideSetting)
|
handler.postDelayed(hideSetting, delayHideSetting)
|
||||||
|
showTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun settingHideNow() {
|
||||||
|
handler.removeCallbacks(hideSetting)
|
||||||
|
handler.postDelayed(hideSetting, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun settingNeverHide() {
|
fun settingNeverHide() {
|
||||||
@@ -271,37 +204,27 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
fun fragmentReady(tag: String) {
|
fun fragmentReady(tag: String) {
|
||||||
ready++
|
ready++
|
||||||
Log.i(TAG, "ready $tag $ready ")
|
Log.i(TAG, "ready $tag $ready ")
|
||||||
if (ready == 7) {
|
if (ready == 6) {
|
||||||
mainFragment.fragmentReady()
|
mainFragment.fragmentReady()
|
||||||
|
showTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showTime() {
|
private fun showTime() {
|
||||||
|
Log.i(TAG, "showTime ${SP.time}")
|
||||||
if (SP.time) {
|
if (SP.time) {
|
||||||
showFragment(timeFragment)
|
timeFragment.show()
|
||||||
} else {
|
} else {
|
||||||
hideFragment(timeFragment)
|
timeFragment.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showFragment(fragment: Fragment) {
|
fun isPlaying() {
|
||||||
if (!fragment.isHidden) {
|
if (errorFragment.isVisible) {
|
||||||
return
|
supportFragmentManager.beginTransaction()
|
||||||
|
.remove(errorFragment)
|
||||||
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.show(fragment)
|
|
||||||
.commitNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideFragment(fragment: Fragment) {
|
|
||||||
if (fragment.isHidden) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.hide(fragment)
|
|
||||||
.commitNow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||||
@@ -314,7 +237,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
||||||
|
|
||||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||||
Log.i(TAG, "onSingleTapConfirmed")
|
|
||||||
switchMainFragment()
|
switchMainFragment()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -362,12 +284,14 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingFragment.isVisible) {
|
Log.i(TAG, "settingFragment ${settingFragment.isVisible}")
|
||||||
return
|
if (!settingFragment.isVisible) {
|
||||||
|
settingFragment.show(supportFragmentManager, "setting")
|
||||||
|
settingDelayHide()
|
||||||
|
} else {
|
||||||
|
handler.removeCallbacks(hideSetting)
|
||||||
|
settingFragment.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
settingFragment.show(supportFragmentManager, TAG)
|
|
||||||
settingDelayHide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val hideSetting = Runnable {
|
private val hideSetting = Runnable {
|
||||||
@@ -376,10 +300,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideSettingFragment() {
|
|
||||||
handler.postDelayed(hideSetting, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun channelUp() {
|
private fun channelUp() {
|
||||||
if (mainFragment.isHidden) {
|
if (mainFragment.isHidden) {
|
||||||
if (SP.channelReversal) {
|
if (SP.channelReversal) {
|
||||||
@@ -419,11 +339,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingFragment.isVisible) {
|
|
||||||
hideSettingFragment()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doubleBackToExitPressedOnce) {
|
if (doubleBackToExitPressedOnce) {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
return
|
return
|
||||||
@@ -437,14 +352,8 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun active() {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
if (settingFragment.isVisible) {
|
Log.i(TAG, "keyCode $keyCode, event $event")
|
||||||
settingDelayHide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onKey(keyCode: Int): Boolean {
|
|
||||||
Log.i(TAG, "keyCode $keyCode")
|
|
||||||
when (keyCode) {
|
when (keyCode) {
|
||||||
KeyEvent.KEYCODE_0 -> {
|
KeyEvent.KEYCODE_0 -> {
|
||||||
showChannel("0")
|
showChannel("0")
|
||||||
@@ -512,7 +421,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_UNKNOWN -> {
|
KeyEvent.KEYCODE_UNKNOWN -> {
|
||||||
// showSetting()
|
showSetting()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +441,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_ENTER -> {
|
KeyEvent.KEYCODE_ENTER -> {
|
||||||
active()
|
|
||||||
switchMainFragment()
|
switchMainFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +449,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> {
|
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||||
active()
|
|
||||||
channelUp()
|
channelUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,7 +457,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||||
active()
|
|
||||||
channelDown()
|
channelDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,28 +465,19 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||||
active()
|
if (!mainFragment.isVisible && !settingFragment.isVisible) {
|
||||||
if (mainFragment.isHidden && !settingFragment.isVisible) {
|
|
||||||
switchMainFragment()
|
switchMainFragment()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||||
active()
|
if (!mainFragment.isVisible && !settingFragment.isVisible) {
|
||||||
if (mainFragment.isHidden && !settingFragment.isVisible) {
|
|
||||||
showSetting()
|
showSetting()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
|
||||||
if (onKey(keyCode)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onKeyDown(keyCode, event)
|
return super.onKeyDown(keyCode, event)
|
||||||
}
|
}
|
||||||
@@ -588,20 +485,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
private fun getAppSignature() = this.appSignature
|
private fun getAppSignature() = this.appSignature
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
Log.i(TAG, "onStart MainActivity")
|
Log.i(TAG, "onStart")
|
||||||
syncTime()
|
|
||||||
super.onStart()
|
super.onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
Log.i(TAG, "onResume")
|
Log.i(TAG, "onResume")
|
||||||
super.onResume()
|
super.onResume()
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResumeFragments() {
|
|
||||||
super.onResumeFragments()
|
|
||||||
mainFragment.changeMenu()
|
|
||||||
|
|
||||||
if (!mainFragment.isHidden) {
|
if (!mainFragment.isHidden) {
|
||||||
handler.postDelayed(hideMain, delayHideMain)
|
handler.postDelayed(hideMain, delayHideMain)
|
||||||
}
|
}
|
||||||
@@ -619,18 +509,16 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestFinished(message: String?) {
|
override fun onRequestFinished(message: String?) {
|
||||||
fragmentReady("request")
|
if (message != null && !errorFragment.isVisible) {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.add(R.id.main_browse_fragment, errorFragment)
|
||||||
|
.commitNow()
|
||||||
|
errorFragment.setErrorContent(message)
|
||||||
|
}
|
||||||
|
fragmentReady("Request")
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val TAG = "MainActivity"
|
const val TAG = "MainActivity"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(key: String) {
|
|
||||||
Log.i(TAG, "$key changed")
|
|
||||||
when (key) {
|
|
||||||
SP.KEY_GRID -> mainFragment.changeMenu()
|
|
||||||
SP.KEY_TIME -> showTime()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,83 +2,71 @@ package com.lizongying.mytv
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.marginBottom
|
import androidx.leanback.app.BrowseSupportFragment
|
||||||
import androidx.core.view.marginStart
|
import androidx.leanback.widget.ArrayObjectAdapter
|
||||||
import androidx.core.view.marginTop
|
import androidx.leanback.widget.HeaderItem
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.leanback.widget.ListRow
|
||||||
|
import androidx.leanback.widget.ListRowPresenter
|
||||||
|
import androidx.leanback.widget.ListRowPresenter.SelectItemViewHolderTask
|
||||||
|
import androidx.leanback.widget.OnItemViewClickedListener
|
||||||
|
import androidx.leanback.widget.OnItemViewSelectedListener
|
||||||
|
import androidx.leanback.widget.Presenter
|
||||||
|
import androidx.leanback.widget.Row
|
||||||
|
import androidx.leanback.widget.RowPresenter
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.lizongying.mytv.api.YSP
|
import com.lizongying.mytv.api.YSP
|
||||||
import com.lizongying.mytv.databinding.MenuBinding
|
|
||||||
import com.lizongying.mytv.databinding.RowBinding
|
|
||||||
import com.lizongying.mytv.models.ProgramType
|
import com.lizongying.mytv.models.ProgramType
|
||||||
import com.lizongying.mytv.models.TVList
|
|
||||||
import com.lizongying.mytv.models.TVListViewModel
|
import com.lizongying.mytv.models.TVListViewModel
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
import com.lizongying.mytv.requests.Request
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class MainFragment : BrowseSupportFragment() {
|
||||||
class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|
||||||
|
|
||||||
private var itemPosition = 0
|
private var itemPosition = 0
|
||||||
|
|
||||||
private var rowList: MutableList<View> = mutableListOf()
|
private var rowsAdapter: ArrayObjectAdapter? = null
|
||||||
|
|
||||||
private var _binding: MenuBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
var tvListViewModel = TVListViewModel()
|
var tvListViewModel = TVListViewModel()
|
||||||
|
|
||||||
private var lastVideoUrl = ""
|
private var lastVideoUrl = ""
|
||||||
|
|
||||||
private lateinit var application: MyTVApplication
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
Log.i(TAG, "onCreate")
|
||||||
private lateinit var gestureDetector: GestureDetector
|
super.onCreate(savedInstanceState)
|
||||||
|
headersState = HEADERS_DISABLED
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
val context = requireContext()
|
|
||||||
_binding = MenuBinding.inflate(inflater, container, false)
|
|
||||||
|
|
||||||
application = requireActivity().applicationContext as MyTVApplication
|
|
||||||
|
|
||||||
binding.menu.layoutParams.width = application.shouldWidthPx()
|
|
||||||
binding.menu.layoutParams.height = application.shouldHeightPx()
|
|
||||||
|
|
||||||
binding.container.setOnClickListener {
|
|
||||||
hideSelf()
|
|
||||||
}
|
|
||||||
|
|
||||||
gestureDetector = GestureDetector(context, GestureListener())
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
// override fun onCreateView(
|
||||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
// inflater: LayoutInflater,
|
||||||
Log.i(TAG, "onSingleTapConfirmed")
|
// container: ViewGroup?,
|
||||||
hideSelf()
|
// savedInstanceState: Bundle?
|
||||||
return true
|
// ): View? {
|
||||||
}
|
// val rootView = super.onCreateView(inflater, container, savedInstanceState)
|
||||||
}
|
// rootView?.setOnClickListener {
|
||||||
|
// Log.i(TAG, "main on click")
|
||||||
|
// fragmentManager!!.beginTransaction().hide(this).commit()
|
||||||
|
// }
|
||||||
|
// mainFragment.view?.setOnClickListener {
|
||||||
|
// Log.i(TAG, "mainFragment on click")
|
||||||
|
// fragmentManager!!.beginTransaction().hide(this).commit()
|
||||||
|
// }
|
||||||
|
// getRowsSupportFragment().view?.setOnClickListener {
|
||||||
|
// Log.i(TAG, "getRowsSupportFragment on click")
|
||||||
|
// fragmentManager!!.beginTransaction().hide(this).commit()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// return rootView
|
||||||
|
// }
|
||||||
|
|
||||||
private fun hideSelf() {
|
override fun onStart() {
|
||||||
requireActivity().supportFragmentManager.beginTransaction()
|
Log.i(TAG, "onStart")
|
||||||
.hide(this)
|
super.onStart()
|
||||||
.commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
@@ -86,247 +74,168 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
|
|
||||||
activity?.let { YSP.init(it) }
|
activity?.let { YSP.init(it) }
|
||||||
|
|
||||||
itemPosition = SP.itemPosition
|
loadRows()
|
||||||
|
|
||||||
view?.post {
|
setupEventListeners()
|
||||||
val content = binding.content
|
|
||||||
|
|
||||||
var idx: Long = 0
|
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
|
||||||
for ((k, v) in TVList.list) {
|
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
|
||||||
val itemBinding: RowBinding =
|
if (tvViewModel.errInfo.value != null
|
||||||
RowBinding.inflate(layoutInflater, content, false)
|
&& tvViewModel.getTV().id == itemPosition
|
||||||
|
) {
|
||||||
val tvListViewModelCurrent = TVListViewModel()
|
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT).show()
|
||||||
for ((idx2, v1) in v.withIndex()) {
|
|
||||||
val tvViewModel = TVViewModel(v1)
|
|
||||||
tvViewModel.setRowPosition(idx.toInt())
|
|
||||||
tvViewModel.setItemPosition(idx2)
|
|
||||||
tvListViewModelCurrent.addTVViewModel(tvViewModel)
|
|
||||||
tvListViewModel.addTVViewModel(tvViewModel)
|
|
||||||
}
|
}
|
||||||
tvListViewModel.maxNum.add(v.size)
|
|
||||||
|
|
||||||
val adapter =
|
|
||||||
CardAdapter(
|
|
||||||
itemBinding.items,
|
|
||||||
this,
|
|
||||||
tvListViewModelCurrent,
|
|
||||||
)
|
|
||||||
rowList.add(itemBinding.items)
|
|
||||||
|
|
||||||
adapter.setItemListener(this)
|
|
||||||
|
|
||||||
itemBinding.header.text = k
|
|
||||||
itemBinding.items.tag = idx.toInt()
|
|
||||||
itemBinding.items.adapter = adapter
|
|
||||||
|
|
||||||
itemBinding.items.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
|
||||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
|
||||||
super.onScrolled(recyclerView, dx, dy)
|
|
||||||
(activity as MainActivity).mainActive()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val itemDecoration = context?.let { ItemDecoration(it) }
|
|
||||||
if (itemDecoration != null) {
|
|
||||||
itemBinding.items.addItemDecoration(itemDecoration)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SP.grid) {
|
|
||||||
itemBinding.items.layoutManager =
|
|
||||||
GridLayoutManager(context, 6)
|
|
||||||
itemBinding.items.layoutParams.height =
|
|
||||||
application.dp2Px(110 * ((tvListViewModelCurrent.size() + 6 - 1) / 6) + 5)
|
|
||||||
} else {
|
|
||||||
itemBinding.items.layoutManager =
|
|
||||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val layoutParams = itemBinding.row.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParams.topMargin = application.dp2Px(11)
|
|
||||||
itemBinding.row.layoutParams = layoutParams
|
|
||||||
itemBinding.row.setOnClickListener {
|
|
||||||
hideSelf()
|
|
||||||
}
|
|
||||||
|
|
||||||
itemBinding.items.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
|
|
||||||
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
|
|
||||||
gestureDetector.onTouchEvent(e)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val layoutParamsHeader =
|
|
||||||
itemBinding.header.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsHeader.topMargin = application.px2Px(itemBinding.header.marginTop)
|
|
||||||
layoutParamsHeader.bottomMargin = application.px2Px(itemBinding.header.marginBottom)
|
|
||||||
layoutParamsHeader.marginStart = application.px2Px(itemBinding.header.marginStart)
|
|
||||||
itemBinding.header.layoutParams = layoutParamsHeader
|
|
||||||
itemBinding.header.textSize = application.px2PxFont(itemBinding.header.textSize)
|
|
||||||
|
|
||||||
content.addView(itemBinding.row)
|
|
||||||
|
|
||||||
idx++
|
|
||||||
}
|
}
|
||||||
|
tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
|
||||||
|
|
||||||
if (itemPosition >= tvListViewModel.size()) {
|
// not first time && channel not change
|
||||||
itemPosition = 0
|
if (tvViewModel.ready.value != null
|
||||||
|
&& tvViewModel.getTV().id == itemPosition
|
||||||
|
&& check(tvViewModel)
|
||||||
|
) {
|
||||||
|
Log.i(TAG, "ready ${tvViewModel.getTV().title}")
|
||||||
|
(activity as? MainActivity)?.play(tvViewModel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
tvViewModel.change.observe(viewLifecycleOwner) { _ ->
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
if (tvViewModel.change.value != null) {
|
||||||
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
|
val title = tvViewModel.getTV().title
|
||||||
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
|
Log.i(TAG, "switch $title")
|
||||||
if (tvViewModel.errInfo.value != null
|
if (tvViewModel.getTV().pid != "") {
|
||||||
&& tvViewModel.getTV().id == itemPosition
|
Log.i(TAG, "request $title")
|
||||||
) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if (tvViewModel.errInfo.value == "") {
|
tvViewModel.let { Request.fetchData(it) }
|
||||||
(activity as? MainActivity)?.showPlayerFragment()
|
|
||||||
(activity as? MainActivity)?.hideErrorFragment()
|
|
||||||
(activity as? MainActivity)?.hideLoadingFragment()
|
|
||||||
} else {
|
|
||||||
(activity as? MainActivity)?.hidePlayerFragment()
|
|
||||||
(activity as? MainActivity)?.hideLoadingFragment()
|
|
||||||
(activity as? MainActivity)?.showErrorFragment(tvViewModel.errInfo.value.toString())
|
|
||||||
}
|
}
|
||||||
}
|
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
||||||
}
|
setSelectedPosition(
|
||||||
tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
|
tvViewModel.getRowPosition(), true,
|
||||||
|
SelectItemViewHolderTask(tvViewModel.getItemPosition())
|
||||||
// not first time && channel not change
|
)
|
||||||
if (tvViewModel.ready.value != null
|
} else {
|
||||||
&& tvViewModel.getTV().id == itemPosition
|
if (check(tvViewModel)) {
|
||||||
&& check(tvViewModel)
|
(activity as? MainActivity)?.play(tvViewModel)
|
||||||
) {
|
|
||||||
Log.i(TAG, "ready ${tvViewModel.getTV().title}")
|
|
||||||
(activity as? MainActivity)?.play(tvViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tvViewModel.change.observe(viewLifecycleOwner) { _ ->
|
|
||||||
if (tvViewModel.change.value != null) {
|
|
||||||
val title = tvViewModel.getTV().title
|
|
||||||
Log.i(TAG, "switch $title")
|
|
||||||
if (tvViewModel.getTV().pid != "") {
|
|
||||||
Log.i(TAG, "request $title")
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
tvViewModel.let { Request.fetchData(it) }
|
|
||||||
}
|
|
||||||
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
||||||
setPosition(
|
setSelectedPosition(
|
||||||
tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
|
tvViewModel.getRowPosition(), true,
|
||||||
|
SelectItemViewHolderTask(tvViewModel.getItemPosition())
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
if (check(tvViewModel)) {
|
|
||||||
// TODO lastVideoUrl
|
|
||||||
(activity as? MainActivity)?.play(tvViewModel)
|
|
||||||
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
|
||||||
setPosition(
|
|
||||||
tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(activity as MainActivity).fragmentReady("MainFragment")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeMenu() {
|
fun toLastPosition() {
|
||||||
if (SP.grid) {
|
setSelectedPosition(
|
||||||
for (i in rowList) {
|
selectedPosition, false,
|
||||||
if (i is RecyclerView) {
|
SelectItemViewHolderTask(tvListViewModel.maxNum[selectedPosition] - 1)
|
||||||
i.layoutManager = GridLayoutManager(context, 6)
|
)
|
||||||
i.layoutParams.height =
|
}
|
||||||
application.dp2Px(110 * (((i.adapter as CardAdapter).getItemCount() + 6 - 1) / 6) + 5)
|
|
||||||
}
|
fun toFirstPosition() {
|
||||||
|
setSelectedPosition(
|
||||||
|
selectedPosition, false,
|
||||||
|
SelectItemViewHolderTask(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startHeadersTransition(withHeaders: Boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadRows() {
|
||||||
|
rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
|
||||||
|
|
||||||
|
val cardPresenter = CardPresenter(context!!)
|
||||||
|
|
||||||
|
var idx: Long = 0
|
||||||
|
for ((k, v) in TVList.list) {
|
||||||
|
val listRowAdapter = ArrayObjectAdapter(cardPresenter)
|
||||||
|
for ((idx2, v1) in v.withIndex()) {
|
||||||
|
val tvViewModel = TVViewModel(v1)
|
||||||
|
tvViewModel.setRowPosition(idx.toInt())
|
||||||
|
tvViewModel.setItemPosition(idx2)
|
||||||
|
tvListViewModel.addTVViewModel(tvViewModel)
|
||||||
|
listRowAdapter.add(tvViewModel)
|
||||||
}
|
}
|
||||||
} else {
|
tvListViewModel.maxNum.add(v.size)
|
||||||
for (i in rowList) {
|
val header = HeaderItem(idx, k)
|
||||||
if (i is RecyclerView) {
|
rowsAdapter!!.add(ListRow(header, listRowAdapter))
|
||||||
i.layoutManager =
|
idx++
|
||||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
}
|
||||||
i.layoutParams.height = application.dp2Px(110 + 5)
|
|
||||||
|
adapter = rowsAdapter
|
||||||
|
|
||||||
|
itemPosition = SP.itemPosition
|
||||||
|
if (itemPosition >= tvListViewModel.size()) {
|
||||||
|
itemPosition = 0
|
||||||
|
}
|
||||||
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prevSource() {
|
||||||
|
view?.post {
|
||||||
|
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
||||||
|
if (tvViewModel != null) {
|
||||||
|
if (tvViewModel.videoUrl.value!!.size > 1) {
|
||||||
|
val videoIndex = tvViewModel.videoIndex.value?.minus(1)
|
||||||
|
if (videoIndex == -1) {
|
||||||
|
tvViewModel.setVideoIndex(tvViewModel.videoUrl.value!!.size - 1)
|
||||||
|
}
|
||||||
|
tvViewModel.changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKey(keyCode: Int): Boolean {
|
fun nextSource() {
|
||||||
if (this.isHidden) {
|
view?.post {
|
||||||
when (keyCode) {
|
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> {
|
if (tvViewModel != null) {
|
||||||
(activity as MainActivity).onKey(keyCode)
|
if (tvViewModel.videoUrl.value!!.size > 1) {
|
||||||
return true
|
val videoIndex = tvViewModel.videoIndex.value?.plus(1)
|
||||||
}
|
if (videoIndex == tvViewModel.videoUrl.value!!.size) {
|
||||||
|
tvViewModel.setVideoIndex(0)
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
}
|
||||||
(activity as MainActivity).onKey(keyCode)
|
tvViewModel.changed()
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemHasFocus(tvViewModel: TVViewModel) {
|
private fun setupEventListeners() {
|
||||||
val row = tvViewModel.getRowPosition()
|
onItemViewClickedListener = ItemViewClickedListener()
|
||||||
|
onItemViewSelectedListener = ItemViewSelectedListener()
|
||||||
|
}
|
||||||
|
|
||||||
for (i in rowList) {
|
private inner class ItemViewClickedListener : OnItemViewClickedListener {
|
||||||
if (i.tag as Int != row) {
|
override fun onItemClicked(
|
||||||
((i as RecyclerView).adapter as CardAdapter).focusable = false
|
itemViewHolder: Presenter.ViewHolder,
|
||||||
(i.adapter as CardAdapter).clear()
|
item: Any,
|
||||||
} else {
|
rowViewHolder: RowPresenter.ViewHolder,
|
||||||
((i as RecyclerView).adapter as CardAdapter).focusable = true
|
row: Row
|
||||||
|
) {
|
||||||
|
if (item is TVViewModel) {
|
||||||
|
if (itemPosition != item.getTV().id) {
|
||||||
|
itemPosition = item.getTV().id
|
||||||
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.switchMainFragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(activity as MainActivity).mainActive()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClicked(tvViewModel: TVViewModel) {
|
private inner class ItemViewSelectedListener : OnItemViewSelectedListener {
|
||||||
if (this.isHidden) {
|
override fun onItemSelected(
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
itemViewHolder: Presenter.ViewHolder?, item: Any?,
|
||||||
return
|
rowViewHolder: RowPresenter.ViewHolder, row: Row
|
||||||
}
|
) {
|
||||||
|
if (item is TVViewModel) {
|
||||||
if (itemPosition != tvViewModel.getTV().id) {
|
tvListViewModel.setItemPositionCurrent(item.getTV().id)
|
||||||
itemPosition = tvViewModel.getTV().id
|
(activity as MainActivity).mainActive()
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed("menu")
|
|
||||||
Log.i(TAG, "onItemClicked ${tvViewModel.getTV().id}")
|
|
||||||
}
|
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPosition() {
|
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition) ?: return
|
|
||||||
val rowPosition = tvViewModel.getRowPosition()
|
|
||||||
val itemPosition = tvViewModel.getItemPosition()
|
|
||||||
setPosition(rowPosition, itemPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPosition(rowPosition: Int, itemPosition: Int) {
|
|
||||||
rowList[rowPosition].post {
|
|
||||||
when (val layoutManager = (rowList[rowPosition] as RecyclerView).layoutManager) {
|
|
||||||
is GridLayoutManager -> {
|
|
||||||
layoutManager.findViewByPosition(
|
|
||||||
itemPosition
|
|
||||||
)?.requestFocus()
|
|
||||||
}
|
|
||||||
|
|
||||||
is LinearLayoutManager -> {
|
|
||||||
layoutManager.findViewByPosition(
|
|
||||||
itemPosition
|
|
||||||
)?.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,7 +257,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fragmentReady() {
|
fun fragmentReady() {
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed("init")
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
|
||||||
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
|
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
|
||||||
updateEPG(tvViewModel)
|
updateEPG(tvViewModel)
|
||||||
@@ -360,7 +269,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
if (itemPosition > -1 && itemPosition < tvListViewModel.size()) {
|
if (itemPosition > -1 && itemPosition < tvListViewModel.size()) {
|
||||||
this.itemPosition = itemPosition
|
this.itemPosition = itemPosition
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed("num")
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, "频道不存在", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "频道不存在", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@@ -374,7 +283,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
itemPosition = tvListViewModel.size() - 1
|
itemPosition = tvListViewModel.size() - 1
|
||||||
}
|
}
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed("prev")
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +294,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
itemPosition = 0
|
itemPosition = 0
|
||||||
}
|
}
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed("next")
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,51 +314,23 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldHasFocus(tvModel: TVViewModel): Boolean {
|
|
||||||
return tvModel == tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHiddenChanged(hidden: Boolean) {
|
|
||||||
Log.i(TAG, "onHiddenChanged $hidden")
|
|
||||||
super.onHiddenChanged(hidden)
|
|
||||||
if (!hidden) {
|
|
||||||
val tvModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
val rowPosition = tvModel?.getRowPosition()
|
|
||||||
val itemPosition = tvModel?.getItemPosition()
|
|
||||||
Log.i(TAG, "toPosition $rowPosition $itemPosition")
|
|
||||||
for (i in rowList) {
|
|
||||||
if (i.tag as Int == rowPosition) {
|
|
||||||
((i as RecyclerView).adapter as CardAdapter).updateEPG()
|
|
||||||
(i.adapter as CardAdapter).focusable = true
|
|
||||||
(i.adapter as CardAdapter).toPosition(itemPosition!!)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
view?.post {
|
|
||||||
for (i in rowList) {
|
|
||||||
((i as RecyclerView).adapter as CardAdapter).focusable = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
Log.i(TAG, "onResume")
|
Log.i(TAG, "onResume")
|
||||||
super.onResume()
|
super.onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
Log.i(TAG, "onStop")
|
||||||
|
super.onStop()
|
||||||
|
SP.itemPosition = itemPosition
|
||||||
|
Log.i(TAG, "$POSITION $itemPosition saved")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.i(TAG, "onDestroy")
|
Log.i(TAG, "onDestroy")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
Log.i(TAG, "onDestroyView")
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "MainFragment"
|
private const val TAG = "MainFragment"
|
||||||
private const val POSITION = "position"
|
private const val POSITION = "position"
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.lizongying.mytv
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.view.WindowManager
|
||||||
|
|
||||||
|
class MyApplication : Application() {
|
||||||
|
private lateinit var displayMetrics: DisplayMetrics
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
|
||||||
|
displayMetrics = DisplayMetrics()
|
||||||
|
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
// windowManager.defaultDisplay.getRealMetrics(displayMetrics)
|
||||||
|
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDisplayMetrics(): DisplayMetrics {
|
||||||
|
return displayMetrics
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.ViewModelStore
|
|
||||||
import androidx.multidex.MultiDex
|
|
||||||
import com.lizongying.mytv.models.MyViewModel
|
|
||||||
|
|
||||||
|
|
||||||
class MyTVApplication : Application() {
|
|
||||||
private lateinit var displayMetrics: DisplayMetrics
|
|
||||||
private lateinit var realDisplayMetrics: DisplayMetrics
|
|
||||||
|
|
||||||
private lateinit var windowManager: WindowManager
|
|
||||||
|
|
||||||
private var width = 0
|
|
||||||
private var height = 0
|
|
||||||
private var shouldWidth = 0
|
|
||||||
private var shouldHeight = 0
|
|
||||||
private var deviation = 0
|
|
||||||
private var ratio = 1.0
|
|
||||||
private var density = 2.0f
|
|
||||||
private var scale = 1.0f
|
|
||||||
|
|
||||||
lateinit var myViewModel: MyViewModel
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
|
|
||||||
displayMetrics = DisplayMetrics()
|
|
||||||
realDisplayMetrics = DisplayMetrics()
|
|
||||||
windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
|
||||||
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
|
||||||
windowManager.defaultDisplay.getRealMetrics(realDisplayMetrics)
|
|
||||||
|
|
||||||
if (realDisplayMetrics.heightPixels > realDisplayMetrics.widthPixels) {
|
|
||||||
width = realDisplayMetrics.heightPixels
|
|
||||||
height = realDisplayMetrics.widthPixels
|
|
||||||
} else {
|
|
||||||
width = realDisplayMetrics.widthPixels
|
|
||||||
height = realDisplayMetrics.heightPixels
|
|
||||||
}
|
|
||||||
|
|
||||||
density = displayMetrics.density
|
|
||||||
|
|
||||||
ratio = if ((width.toDouble() / height) < (16.0 / 9)) {
|
|
||||||
width * 2 / 1920.0 / density
|
|
||||||
} else {
|
|
||||||
height * 2 / 1080.0 / density
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((width.toDouble() / height) < (16.0 / 9.0)) {
|
|
||||||
ratio = width * 2 / 1920.0 / density
|
|
||||||
shouldWidth = width
|
|
||||||
shouldHeight = (width * 9.0 / 16.0).toInt()
|
|
||||||
} else {
|
|
||||||
ratio = height * 2 / 1080.0 / density
|
|
||||||
shouldHeight = height
|
|
||||||
shouldWidth = (height * 16.0 / 9.0).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
deviation = width - Resources.getSystem().displayMetrics.widthPixels
|
|
||||||
scale = Resources.getSystem().displayMetrics.scaledDensity
|
|
||||||
|
|
||||||
myViewModel = ViewModelProvider(
|
|
||||||
ViewModelStore(),
|
|
||||||
ViewModelProvider.NewInstanceFactory()
|
|
||||||
)[MyViewModel::class.java]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDisplayMetrics(): DisplayMetrics {
|
|
||||||
return displayMetrics
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRealDisplayMetrics(): DisplayMetrics {
|
|
||||||
return realDisplayMetrics
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldWidthPx(): Int {
|
|
||||||
return shouldWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldHeightPx(): Int {
|
|
||||||
return shouldHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getWidth(): Int {
|
|
||||||
return width
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHeight(): Int {
|
|
||||||
return height
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDeviation(): Int {
|
|
||||||
return deviation
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRatio(): Double {
|
|
||||||
return ratio
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dp2Px(dp: Int): Int {
|
|
||||||
return (dp * ratio * density + 0.5f).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun px2Px(px: Int): Int {
|
|
||||||
return (px * ratio + 0.5f).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun px2PxFont(px: Float): Float {
|
|
||||||
return (px * ratio / scale).toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sp2Px(sp: Float): Float {
|
|
||||||
return (sp * ratio * scale).toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context?) {
|
|
||||||
super.attachBaseContext(base)
|
|
||||||
MultiDex.install(base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
|
|
||||||
interface OnSharedPreferenceChangeListener {
|
|
||||||
fun onSharedPreferenceChanged(key: String)
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,8 @@ package com.lizongying.mytv
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
import android.view.SurfaceView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
@@ -15,37 +17,45 @@ import androidx.media3.common.VideoSize
|
|||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
|
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||||
import com.lizongying.mytv.databinding.PlayerBinding
|
import com.lizongying.mytv.databinding.PlayerBinding
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
|
|
||||||
|
|
||||||
class PlayerFragment : Fragment() {
|
class PlayerFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
private var _binding: PlayerBinding? = null
|
private var _binding: PlayerBinding? = null
|
||||||
private var playerView: PlayerView? = null
|
private var playerView: PlayerView? = null
|
||||||
private var tvViewModel: TVViewModel? = null
|
private var tvViewModel: TVViewModel? = null
|
||||||
private val aspectRatio = 16f / 9f
|
private val aspectRatio = 16f / 9f
|
||||||
|
|
||||||
|
|
||||||
|
private lateinit var surfaceView: SurfaceView
|
||||||
|
private lateinit var surfaceHolder: SurfaceHolder
|
||||||
|
private var exoPlayer: SimpleExoPlayer? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = PlayerBinding.inflate(inflater, container, false)
|
_binding = PlayerBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
playerView = _binding!!.playerView
|
if (Utils.isTmallDevice()) {
|
||||||
|
_binding!!.playerView.visibility = View.GONE
|
||||||
|
surfaceView = _binding!!.surfaceView
|
||||||
|
surfaceHolder = surfaceView.holder
|
||||||
|
surfaceHolder.addCallback(this)
|
||||||
|
} else {
|
||||||
|
_binding!!.surfaceView.visibility = View.GONE
|
||||||
|
playerView = _binding!!.playerView
|
||||||
|
}
|
||||||
|
|
||||||
playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object :
|
playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object :
|
||||||
ViewTreeObserver.OnGlobalLayoutListener {
|
ViewTreeObserver.OnGlobalLayoutListener {
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
override fun onGlobalLayout() {
|
override fun onGlobalLayout() {
|
||||||
playerView!!.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
playerView!!.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||||
|
|
||||||
// val renderersFactory = context?.let { DefaultRenderersFactory(it) }
|
|
||||||
// renderersFactory?.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
|
|
||||||
|
|
||||||
playerView!!.player = activity?.let {
|
playerView!!.player = activity?.let {
|
||||||
ExoPlayer.Builder(it)
|
ExoPlayer.Builder(it)
|
||||||
// .setRenderersFactory(renderersFactory!!)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
playerView!!.player?.playWhenReady = true
|
playerView!!.player?.playWhenReady = true
|
||||||
@@ -68,22 +78,21 @@ class PlayerFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onPlayerError(error: PlaybackException) {
|
override fun onPlayerError(error: PlaybackException) {
|
||||||
super.onPlayerError(error)
|
super.onPlayerError(error)
|
||||||
|
|
||||||
Log.e(TAG, "PlaybackException $error")
|
Log.e(TAG, "PlaybackException $error")
|
||||||
val err = "播放错误"
|
tvViewModel?.changed()
|
||||||
tvViewModel?.setErrInfo(err)
|
|
||||||
tvViewModel?.changed("retry")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||||
super.onIsPlayingChanged(isPlaying)
|
super.onIsPlayingChanged(isPlaying)
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
tvViewModel?.setErrInfo("")
|
(activity as MainActivity).isPlaying()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
(activity as MainActivity).fragmentReady("PlayerFragment")
|
||||||
return _binding!!.root
|
return _binding!!.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +102,10 @@ class PlayerFragment : Fragment() {
|
|||||||
playerView?.player?.run {
|
playerView?.player?.run {
|
||||||
setMediaItem(MediaItem.fromUri(tvViewModel.getVideoUrlCurrent()))
|
setMediaItem(MediaItem.fromUri(tvViewModel.getVideoUrlCurrent()))
|
||||||
prepare()
|
prepare()
|
||||||
volume = tvViewModel.getTV().volume
|
}
|
||||||
|
exoPlayer?.run {
|
||||||
|
setMediaItem(com.google.android.exoplayer2.MediaItem.fromUri(tvViewModel.getVideoUrlCurrent()))
|
||||||
|
prepare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +117,11 @@ class PlayerFragment : Fragment() {
|
|||||||
playerView!!.player?.prepare()
|
playerView!!.player?.prepare()
|
||||||
playerView!!.player?.play()
|
playerView!!.player?.play()
|
||||||
}
|
}
|
||||||
|
if (exoPlayer?.isPlaying == false) {
|
||||||
|
Log.i(TAG, "replay")
|
||||||
|
exoPlayer?.prepare()
|
||||||
|
exoPlayer?.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -117,6 +134,9 @@ class PlayerFragment : Fragment() {
|
|||||||
if (playerView != null && playerView!!.player?.isPlaying == true) {
|
if (playerView != null && playerView!!.player?.isPlaying == true) {
|
||||||
playerView!!.player?.stop()
|
playerView!!.player?.stop()
|
||||||
}
|
}
|
||||||
|
if (exoPlayer?.isPlaying == true) {
|
||||||
|
exoPlayer?.stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
@@ -124,6 +144,7 @@ class PlayerFragment : Fragment() {
|
|||||||
if (playerView != null) {
|
if (playerView != null) {
|
||||||
playerView!!.player?.release()
|
playerView!!.player?.release()
|
||||||
}
|
}
|
||||||
|
exoPlayer?.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
@@ -132,6 +153,18 @@ class PlayerFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "PlayerFragment"
|
private const val TAG = "PlaybackVideoFragment"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
|
exoPlayer = SimpleExoPlayer.Builder(requireContext()).build()
|
||||||
|
exoPlayer?.setVideoSurfaceHolder(surfaceHolder)
|
||||||
|
exoPlayer?.playWhenReady = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+45
-344
@@ -1,10 +1,9 @@
|
|||||||
package com.lizongying.mytv.requests
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.lizongying.mytv.Utils
|
|
||||||
import com.lizongying.mytv.Utils.getDateFormat
|
import com.lizongying.mytv.Utils.getDateFormat
|
||||||
import com.lizongying.mytv.api.ApiClient
|
import com.lizongying.mytv.api.ApiClient
|
||||||
import com.lizongying.mytv.api.Auth
|
import com.lizongying.mytv.api.Auth
|
||||||
@@ -18,14 +17,12 @@ import com.lizongying.mytv.api.KvcollectRequest
|
|||||||
import com.lizongying.mytv.api.KvcollectRequest2
|
import com.lizongying.mytv.api.KvcollectRequest2
|
||||||
import com.lizongying.mytv.api.LiveInfo
|
import com.lizongying.mytv.api.LiveInfo
|
||||||
import com.lizongying.mytv.api.LiveInfoRequest
|
import com.lizongying.mytv.api.LiveInfoRequest
|
||||||
import com.lizongying.mytv.api.Token2
|
|
||||||
import com.lizongying.mytv.api.YSP
|
import com.lizongying.mytv.api.YSP
|
||||||
import com.lizongying.mytv.api.YSPApiService
|
import com.lizongying.mytv.api.YSPApiService
|
||||||
import com.lizongying.mytv.api.YSPBtraceService
|
import com.lizongying.mytv.api.YSPBtraceService
|
||||||
import com.lizongying.mytv.api.YSPJceService
|
import com.lizongying.mytv.api.YSPJceService
|
||||||
import com.lizongying.mytv.api.YSPProtoService
|
import com.lizongying.mytv.api.YSPProtoService
|
||||||
import com.lizongying.mytv.api.YSPTokenService
|
import com.lizongying.mytv.api.YSPTokenService
|
||||||
import com.lizongying.mytv.models.TVList
|
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
|
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
|
||||||
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgramModel
|
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgramModel
|
||||||
@@ -43,7 +40,6 @@ import kotlin.random.Random
|
|||||||
object Request {
|
object Request {
|
||||||
private const val TAG = "Request"
|
private const val TAG = "Request"
|
||||||
private var yspTokenService: YSPTokenService = ApiClient().yspTokenService
|
private var yspTokenService: YSPTokenService = ApiClient().yspTokenService
|
||||||
private var yspToken2Service: YSPApiService = ApiClient().yspToken2Service
|
|
||||||
private var yspApiService: YSPApiService = ApiClient().yspApiService
|
private var yspApiService: YSPApiService = ApiClient().yspApiService
|
||||||
private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService
|
private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService
|
||||||
private var yspBtraceService2: YSPBtraceService = ApiClient().yspBtraceService2
|
private var yspBtraceService2: YSPBtraceService = ApiClient().yspBtraceService2
|
||||||
@@ -56,9 +52,8 @@ object Request {
|
|||||||
private var token = ""
|
private var token = ""
|
||||||
private var tokenFH = ""
|
private var tokenFH = ""
|
||||||
|
|
||||||
private var needAuth = true
|
private var needAuth = false
|
||||||
private var needToken = false
|
private var needToken = false
|
||||||
private var needToken2 = true
|
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private lateinit var btraceRunnable: BtraceRunnable
|
private lateinit var btraceRunnable: BtraceRunnable
|
||||||
@@ -77,7 +72,6 @@ object Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var call: Call<LiveInfo>? = null
|
private var call: Call<LiveInfo>? = null
|
||||||
private var callToken: Call<Token2>? = null
|
|
||||||
private var callAuth: Call<Auth>? = null
|
private var callAuth: Call<Auth>? = null
|
||||||
private var callInfo: Call<Info>? = null
|
private var callInfo: Call<Info>? = null
|
||||||
private var callFAuth: Call<FAuth>? = null
|
private var callFAuth: Call<FAuth>? = null
|
||||||
@@ -88,117 +82,11 @@ object Request {
|
|||||||
private fun cancelCall() {
|
private fun cancelCall() {
|
||||||
call?.cancel()
|
call?.cancel()
|
||||||
callAuth?.cancel()
|
callAuth?.cancel()
|
||||||
callToken?.cancel()
|
|
||||||
callInfo?.cancel()
|
callInfo?.cancel()
|
||||||
callFAuth?.cancel()
|
callFAuth?.cancel()
|
||||||
callPage?.cancel()
|
callPage?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun fetchToken(tvModel: TVViewModel, cookie: String) {
|
|
||||||
cancelCall()
|
|
||||||
|
|
||||||
val title = tvModel.getTV().title
|
|
||||||
|
|
||||||
callToken = yspToken2Service.getToken("guid=${YSP.getGuid()}; $cookie", "519748109", YSP.getGuid(), "59306155", "b42702bf7309a179d102f3d51b1add2fda0bc7ada64cb801" ,"1", YSP.getTimeStr())
|
|
||||||
callToken?.enqueue(object : Callback<Token2> {
|
|
||||||
override fun onResponse(call: Call<Token2>, response: Response<Token2>) {
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
val liveInfo = response.body()
|
|
||||||
|
|
||||||
if (liveInfo?.data?.token != null) {
|
|
||||||
Log.i(TAG, "token ${liveInfo.data.token}")
|
|
||||||
YSP.token2 = liveInfo.data.token
|
|
||||||
|
|
||||||
YSP.getTokenData(tvModel)
|
|
||||||
|
|
||||||
fetchAuth(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "$title token error")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
|
||||||
tvModel.retryTimes++
|
|
||||||
if (tvModel.getTV().needToken) {
|
|
||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
|
||||||
tvModel.tokenYSPRetryTimes++
|
|
||||||
tvModel.needGetToken = true
|
|
||||||
fetchToken(tvModel)
|
|
||||||
} else {
|
|
||||||
if (!tvModel.getTV().mustToken) {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "认证结果错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "$title token status error")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
|
||||||
tvModel.retryTimes++
|
|
||||||
if (tvModel.getTV().needToken) {
|
|
||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
|
||||||
tvModel.tokenYSPRetryTimes++
|
|
||||||
tvModel.needGetToken = true
|
|
||||||
fetchToken(tvModel)
|
|
||||||
} else {
|
|
||||||
if (!tvModel.getTV().mustToken) {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "认证状态错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<Token2>, t: Throwable) {
|
|
||||||
Log.e(TAG, "$title token request error $t")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
|
||||||
tvModel.retryTimes++
|
|
||||||
if (tvModel.getTV().needToken) {
|
|
||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
|
||||||
tvModel.tokenYSPRetryTimes++
|
|
||||||
tvModel.needGetToken = true
|
|
||||||
fetchToken(tvModel)
|
|
||||||
} else {
|
|
||||||
if (!tvModel.getTV().mustToken) {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "认证请求错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchAuth(tvModel: TVViewModel, cookie: String) {
|
private fun fetchAuth(tvModel: TVViewModel, cookie: String) {
|
||||||
cancelCall()
|
cancelCall()
|
||||||
|
|
||||||
@@ -213,11 +101,11 @@ object Request {
|
|||||||
val liveInfo = response.body()
|
val liveInfo = response.body()
|
||||||
|
|
||||||
if (liveInfo?.data?.token != null) {
|
if (liveInfo?.data?.token != null) {
|
||||||
Log.i(TAG, "auth ${liveInfo.data.token}")
|
Log.i(TAG, "token ${liveInfo.data.token}")
|
||||||
YSP.token = liveInfo.data.token
|
YSP.token = liveInfo.data.token
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "$title auth error")
|
Log.e(TAG, "$title token error")
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
tvModel.retryTimes++
|
tvModel.retryTimes++
|
||||||
if (tvModel.getTV().needToken) {
|
if (tvModel.getTV().needToken) {
|
||||||
@@ -228,19 +116,11 @@ object Request {
|
|||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "认证结果错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -255,19 +135,11 @@ object Request {
|
|||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "认证状态错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,19 +156,11 @@ object Request {
|
|||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "认证请求错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -305,7 +169,7 @@ object Request {
|
|||||||
private fun fetchVideo(tvModel: TVViewModel, cookie: String) {
|
private fun fetchVideo(tvModel: TVViewModel, cookie: String) {
|
||||||
cancelCall()
|
cancelCall()
|
||||||
|
|
||||||
if (Request::btraceRunnable.isInitialized) {
|
if (::btraceRunnable.isInitialized) {
|
||||||
handler.removeCallbacks(btraceRunnable)
|
handler.removeCallbacks(btraceRunnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,14 +180,8 @@ object Request {
|
|||||||
val request = LiveInfoRequest(data)
|
val request = LiveInfoRequest(data)
|
||||||
call = request.let {
|
call = request.let {
|
||||||
yspApiService.getLiveInfo(
|
yspApiService.getLiveInfo(
|
||||||
"guid=${YSP.getGuid()}; gr_user_id=1; $cookie; newLogin=1; nseqId=${YSP.nseqId}; nrequest-id=${YSP.nrequest_id}",
|
"guid=${YSP.getGuid()}; $cookie",
|
||||||
YSP.token,
|
YSP.token,
|
||||||
YSP.yspsdkinput,
|
|
||||||
YSP.openapi_signature,
|
|
||||||
YSP.yspticket,
|
|
||||||
"${YSP.nseqId}",
|
|
||||||
YSP.nrequest_id,
|
|
||||||
"519748109",
|
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -363,42 +221,24 @@ object Request {
|
|||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
||||||
tvModel.tokenYSPRetryTimes++
|
tvModel.tokenYSPRetryTimes++
|
||||||
tvModel.needGetToken = true
|
tvModel.needGetToken = true
|
||||||
if (needAuth) {
|
fetchVideo(tvModel)
|
||||||
fetchAuth(tvModel)
|
// fetchAuth(tvModel)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "结果错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") {
|
if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") {
|
||||||
val err = "版权错误"
|
Log.e(TAG, "$title error ${liveInfo.data.errinfo}")
|
||||||
Log.e(TAG, "$title $err")
|
tvModel.setErrInfo(liveInfo.data.errinfo)
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "$title url error $request $liveInfo")
|
Log.e(TAG, "$title url error $request $liveInfo")
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
@@ -407,35 +247,18 @@ object Request {
|
|||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
||||||
tvModel.tokenYSPRetryTimes++
|
tvModel.tokenYSPRetryTimes++
|
||||||
tvModel.needGetToken = true
|
tvModel.needGetToken = true
|
||||||
if (needAuth) {
|
fetchVideo(tvModel)
|
||||||
fetchAuth(tvModel)
|
// fetchAuth(tvModel)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "其他错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,35 +270,18 @@ object Request {
|
|||||||
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
||||||
tvModel.tokenYSPRetryTimes++
|
tvModel.tokenYSPRetryTimes++
|
||||||
tvModel.needGetToken = true
|
tvModel.needGetToken = true
|
||||||
if (needAuth) {
|
fetchVideo(tvModel)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val err = "错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
// fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "状态错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,82 +298,16 @@ object Request {
|
|||||||
} else {
|
} else {
|
||||||
if (!tvModel.getTV().mustToken) {
|
if (!tvModel.getTV().mustToken) {
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val err = "请求错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchToken(tvModel: TVViewModel) {
|
|
||||||
cancelCall()
|
|
||||||
if (tvModel.needGetToken) {
|
|
||||||
callInfo = yspTokenService.getInfo("")
|
|
||||||
callInfo?.enqueue(object : Callback<Info> {
|
|
||||||
override fun onResponse(call: Call<Info>, response: Response<Info>) {
|
|
||||||
if (response.isSuccessful && response.body()?.data?.token != null) {
|
|
||||||
token = response.body()?.data?.token!!
|
|
||||||
Log.i(TAG, "info success $token")
|
|
||||||
tvModel.needGetToken = false
|
|
||||||
tvModel.tokenYSPRetryTimes = 0
|
|
||||||
val cookie =
|
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token"
|
|
||||||
fetchAuth(tvModel, cookie)
|
|
||||||
} else if (response.code() == 304) {
|
|
||||||
tvModel.needGetToken = false
|
|
||||||
tvModel.tokenYSPRetryTimes = 0
|
|
||||||
val cookie =
|
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109; yspopenid=$openid; vusession=$token"
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "info status error")
|
|
||||||
if (tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
|
||||||
tvModel.tokenYSPRetryTimes++
|
|
||||||
fetchToken(tvModel)
|
|
||||||
} else {
|
|
||||||
if (!tvModel.getTV().mustToken) {
|
|
||||||
val cookie =
|
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109"
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<Info>, t: Throwable) {
|
|
||||||
Log.e(TAG, "info request error $t")
|
|
||||||
if (tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
|
|
||||||
tvModel.tokenYSPRetryTimes++
|
|
||||||
fetchAuth(tvModel)
|
|
||||||
} else {
|
|
||||||
if (!tvModel.getTV().mustToken) {
|
|
||||||
val cookie =
|
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109"
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
val cookie =
|
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token"
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchAuth(tvModel: TVViewModel) {
|
private fun fetchAuth(tvModel: TVViewModel) {
|
||||||
cancelCall()
|
cancelCall()
|
||||||
if (tvModel.needGetToken) {
|
if (tvModel.needGetToken) {
|
||||||
@@ -598,8 +338,6 @@ object Request {
|
|||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,15 +353,13 @@ object Request {
|
|||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; yspopenid=$openid; vusession=$token"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token"
|
||||||
fetchAuth(tvModel, cookie)
|
fetchAuth(tvModel, cookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -659,8 +395,6 @@ object Request {
|
|||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,8 +410,6 @@ object Request {
|
|||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -713,10 +445,6 @@ object Request {
|
|||||||
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
|
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
|
||||||
tvModel.tokenFHRetryTimes++
|
tvModel.tokenFHRetryTimes++
|
||||||
fetchFAuth(tvModel)
|
fetchFAuth(tvModel)
|
||||||
} else {
|
|
||||||
val err = "状态错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -726,10 +454,6 @@ object Request {
|
|||||||
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
|
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
|
||||||
tvModel.tokenFHRetryTimes++
|
tvModel.tokenFHRetryTimes++
|
||||||
fetchFAuth(tvModel)
|
fetchFAuth(tvModel)
|
||||||
} else {
|
|
||||||
val err = "请求错误"
|
|
||||||
Log.e(TAG, "$title $err")
|
|
||||||
tvModel.setErrInfo(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -745,42 +469,19 @@ object Request {
|
|||||||
if (token == "") {
|
if (token == "") {
|
||||||
tvModel.needGetToken = true
|
tvModel.needGetToken = true
|
||||||
}
|
}
|
||||||
if (needToken2) {
|
if (needAuth) {
|
||||||
if (needAuth) {
|
fetchAuth(tvModel)
|
||||||
fetchToken(tvModel)
|
|
||||||
} else {
|
|
||||||
fetchAuth(tvModel)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel)
|
||||||
fetchAuth(tvModel)
|
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val cookie =
|
val cookie =
|
||||||
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124"
|
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; updateProtocol=1; deviceModel=120"
|
||||||
|
if (needAuth) {
|
||||||
if (needToken2) {
|
fetchAuth(tvModel, cookie)
|
||||||
if (needAuth) {
|
|
||||||
fetchToken(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
fetchAuth(tvModel, cookie)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (needAuth) {
|
fetchVideo(tvModel, cookie)
|
||||||
fetchAuth(tvModel, cookie)
|
|
||||||
} else {
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// if (needAuth) {
|
|
||||||
// fetchAuth(tvModel, cookie)
|
|
||||||
// } else {
|
|
||||||
// fetchVideo(tvModel, cookie)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,7 +600,7 @@ object Request {
|
|||||||
seq = tvModel.seq,
|
seq = tvModel.seq,
|
||||||
durl = url,
|
durl = url,
|
||||||
url = url,
|
url = url,
|
||||||
// _dc = "",
|
_dc = randomNumber,
|
||||||
)
|
)
|
||||||
|
|
||||||
val e =
|
val e =
|
||||||
@@ -931,7 +632,7 @@ object Request {
|
|||||||
val guid = YSP.getGuid()
|
val guid = YSP.getGuid()
|
||||||
val pid = tvModel.getTV().pid
|
val pid = tvModel.getTV().pid
|
||||||
val sid = tvModel.getTV().sid
|
val sid = tvModel.getTV().sid
|
||||||
// val randomNumber = Random.nextDouble()
|
val randomNumber = Random.nextDouble()
|
||||||
val url = tvModel.getTV().videoUrl.first()
|
val url = tvModel.getTV().videoUrl.first()
|
||||||
|
|
||||||
val r = KvcollectRequest2(
|
val r = KvcollectRequest2(
|
||||||
@@ -946,12 +647,12 @@ object Request {
|
|||||||
seq = tvModel.seq,
|
seq = tvModel.seq,
|
||||||
durl = url,
|
durl = url,
|
||||||
url = url,
|
url = url,
|
||||||
_dc = "",
|
_dc = randomNumber,
|
||||||
)
|
)
|
||||||
|
|
||||||
// val e =
|
val e =
|
||||||
// "BossId=${r.BossId}&Pwd=${r.Pwd}&_dc=${r._dc}&cdn=${r.cdn}&cmd=${r.cmd}&defn=${r.defn}&downspeed=${r.downspeed}&durl=${r.durl}&errcode=${r.errcode}&fact1=${r.fact1}&firstreport=${r.firstreport}&fplayerver=${r.fplayerver}&ftime=${r.ftime}&geturltime=${r.geturltime}&guid=${r.guid}&hc_openid=${r.hc_openid}&hh_ua=${r.hh_ua}&live_type=${r.live_type}&livepid=${r.livepid}&login_type=${r.login_type}&open_id=${r.open_id}&openid=${r.openid}&platform=${r.platform}&playno=${r.playno}&prd=${r.prd}&prog=${r.prog}&rand_str=${r.rand_str}&sRef=${r.sRef}&sUrl=${r.sUrl}&sdtfrom=${r.sdtfrom}&seq=${r.seq}&url=${r.url}&viewid=${r.viewid}"
|
"BossId=${r.BossId}&Pwd=${r.Pwd}&_dc=${r._dc}&cdn=${r.cdn}&cmd=${r.cmd}&defn=${r.defn}&downspeed=${r.downspeed}&durl=${r.durl}&errcode=${r.errcode}&fact1=${r.fact1}&firstreport=${r.firstreport}&fplayerver=${r.fplayerver}&ftime=${r.ftime}&geturltime=${r.geturltime}&guid=${r.guid}&hc_openid=${r.hc_openid}&hh_ua=${r.hh_ua}&live_type=${r.live_type}&livepid=${r.livepid}&login_type=${r.login_type}&open_id=${r.open_id}&openid=${r.openid}&platform=${r.platform}&playno=${r.playno}&prd=${r.prd}&prog=${r.prog}&rand_str=${r.rand_str}&sRef=${r.sRef}&sUrl=${r.sUrl}&sdtfrom=${r.sdtfrom}&seq=${r.seq}&url=${r.url}&viewid=${r.viewid}"
|
||||||
// r.signature = YSP.getAuthSignature(e)
|
r.signature = YSP.getAuthSignature(e)
|
||||||
|
|
||||||
callBtracePage = yspBtraceService3.kvcollect3(
|
callBtracePage = yspBtraceService3.kvcollect3(
|
||||||
guid = r.guid,
|
guid = r.guid,
|
||||||
@@ -960,18 +661,18 @@ object Request {
|
|||||||
livepid = r.livepid,
|
livepid = r.livepid,
|
||||||
sUrl = r.sUrl,
|
sUrl = r.sUrl,
|
||||||
playno = r.playno,
|
playno = r.playno,
|
||||||
// rand_str = r.rand_str,
|
rand_str = r.rand_str,
|
||||||
ftime = r.ftime,
|
ftime = r.ftime,
|
||||||
seq = "${r.seq}",
|
seq = "${r.seq}",
|
||||||
durl = r.durl,
|
durl = r.durl,
|
||||||
// url = r.url,
|
url = r.url,
|
||||||
_dc = "${r._dc}",
|
_dc = "${r._dc}",
|
||||||
// signature = r.signature
|
signature = r.signature
|
||||||
)
|
)
|
||||||
callBtracePage?.enqueue(object : Callback<Void> {
|
callBtracePage?.enqueue(object : Callback<Void> {
|
||||||
override fun onResponse(call: Call<Void>, response: Response<Void>) {
|
override fun onResponse(call: Call<Void>, response: Response<Void>) {
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
Log.i(TAG, "$title kvcollect success")
|
Log.d(TAG, "$title kvcollect success")
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "$title kvcollect status error")
|
Log.e(TAG, "$title kvcollect status error")
|
||||||
}
|
}
|
||||||
@@ -1114,6 +815,6 @@ object Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setRequestListener(listener: RequestListener) {
|
fun setRequestListener(listener: RequestListener) {
|
||||||
Request.listener = listener
|
this.listener = listener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,12 +13,12 @@ object SP {
|
|||||||
// If use channel num to select channel or not
|
// If use channel num to select channel or not
|
||||||
private const val KEY_CHANNEL_NUM = "channel_num"
|
private const val KEY_CHANNEL_NUM = "channel_num"
|
||||||
|
|
||||||
const val KEY_TIME = "time"
|
private const val KEY_TIME = "time"
|
||||||
|
|
||||||
// If start app on device boot or not
|
// If start app on device boot or not
|
||||||
private const val KEY_BOOT_STARTUP = "boot_startup"
|
private const val KEY_BOOT_STARTUP = "boot_startup"
|
||||||
|
|
||||||
const val KEY_GRID = "grid"
|
private const val KEY_GRID = "grid"
|
||||||
|
|
||||||
// Position in list of the selected channel item
|
// Position in list of the selected channel item
|
||||||
private const val KEY_POSITION = "position"
|
private const val KEY_POSITION = "position"
|
||||||
@@ -28,8 +28,6 @@ object SP {
|
|||||||
|
|
||||||
private lateinit var sp: SharedPreferences
|
private lateinit var sp: SharedPreferences
|
||||||
|
|
||||||
private var listener: OnSharedPreferenceChangeListener? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method must be invoked as early as possible(At least before using the keys)
|
* The method must be invoked as early as possible(At least before using the keys)
|
||||||
*/
|
*/
|
||||||
@@ -37,10 +35,6 @@ object SP {
|
|||||||
sp = context.getSharedPreferences(SP_FILE_NAME, Context.MODE_PRIVATE)
|
sp = context.getSharedPreferences(SP_FILE_NAME, Context.MODE_PRIVATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnSharedPreferenceChangeListener(listener: OnSharedPreferenceChangeListener) {
|
|
||||||
this.listener = listener
|
|
||||||
}
|
|
||||||
|
|
||||||
var channelReversal: Boolean
|
var channelReversal: Boolean
|
||||||
get() = sp.getBoolean(KEY_CHANNEL_REVERSAL, false)
|
get() = sp.getBoolean(KEY_CHANNEL_REVERSAL, false)
|
||||||
set(value) = sp.edit().putBoolean(KEY_CHANNEL_REVERSAL, value).apply()
|
set(value) = sp.edit().putBoolean(KEY_CHANNEL_REVERSAL, value).apply()
|
||||||
@@ -51,12 +45,7 @@ object SP {
|
|||||||
|
|
||||||
var time: Boolean
|
var time: Boolean
|
||||||
get() = sp.getBoolean(KEY_TIME, true)
|
get() = sp.getBoolean(KEY_TIME, true)
|
||||||
set(value) {
|
set(value) = sp.edit().putBoolean(KEY_TIME, value).apply()
|
||||||
if (value != this.time) {
|
|
||||||
sp.edit().putBoolean(KEY_TIME, value).apply()
|
|
||||||
listener?.onSharedPreferenceChanged(KEY_TIME)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bootStartup: Boolean
|
var bootStartup: Boolean
|
||||||
get() = sp.getBoolean(KEY_BOOT_STARTUP, false)
|
get() = sp.getBoolean(KEY_BOOT_STARTUP, false)
|
||||||
@@ -64,12 +53,7 @@ object SP {
|
|||||||
|
|
||||||
var grid: Boolean
|
var grid: Boolean
|
||||||
get() = sp.getBoolean(KEY_GRID, false)
|
get() = sp.getBoolean(KEY_GRID, false)
|
||||||
set(value) {
|
set(value) = sp.edit().putBoolean(KEY_GRID, value).apply()
|
||||||
if (value != this.grid) {
|
|
||||||
sp.edit().putBoolean(KEY_GRID, value).apply()
|
|
||||||
listener?.onSharedPreferenceChanged(KEY_GRID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemPosition: Int
|
var itemPosition: Int
|
||||||
get() = sp.getInt(KEY_POSITION, 0)
|
get() = sp.getInt(KEY_POSITION, 0)
|
||||||
|
|||||||
@@ -1,23 +1,11 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
|
||||||
import android.view.View.VISIBLE
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.marginEnd
|
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.lizongying.mytv.api.YSP
|
|
||||||
import com.lizongying.mytv.databinding.SettingBinding
|
import com.lizongying.mytv.databinding.SettingBinding
|
||||||
|
|
||||||
|
|
||||||
@@ -33,11 +21,6 @@ class SettingFragment : DialogFragment() {
|
|||||||
dialog?.window?.apply {
|
dialog?.window?.apply {
|
||||||
addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||||
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
attributes.layoutInDisplayCutoutMode =
|
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
|
||||||
setAttributes(attributes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,156 +71,35 @@ class SettingFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.switchGrid.run {
|
updateManager = UpdateManager(context, this, context.appVersionCode)
|
||||||
isChecked = SP.grid
|
binding.checkVersion.setOnClickListener(
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
OnClickListenerCheckVersion(
|
||||||
SP.grid = isChecked
|
activity as MainActivity,
|
||||||
(activity as MainActivity).settingDelayHide()
|
updateManager
|
||||||
}
|
)
|
||||||
}
|
|
||||||
|
|
||||||
binding.checkVersion.setOnClickListener {
|
|
||||||
(activity as MainActivity).settingDelayHide()
|
|
||||||
requestInstallPermissions()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.clear.setOnClickListener {
|
|
||||||
(requireActivity() as MainActivity).syncTime()
|
|
||||||
SP.guid = ""
|
|
||||||
YSP.getGuid()
|
|
||||||
}
|
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
|
||||||
val textSize = application.px2PxFont(binding.switchChannelReversal.textSize)
|
|
||||||
|
|
||||||
binding.content.layoutParams.width =
|
|
||||||
application.px2Px(binding.content.layoutParams.width)
|
|
||||||
binding.content.setPadding(
|
|
||||||
application.px2Px(binding.content.paddingLeft),
|
|
||||||
application.px2Px(binding.content.paddingTop),
|
|
||||||
application.px2Px(binding.content.paddingRight),
|
|
||||||
application.px2Px(binding.content.paddingBottom)
|
|
||||||
)
|
)
|
||||||
binding.name.textSize = application.px2PxFont(binding.name.textSize)
|
|
||||||
binding.version.textSize = textSize
|
|
||||||
val layoutParamsVersion = binding.version.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsVersion.topMargin = application.px2Px(binding.version.marginTop)
|
|
||||||
binding.version.layoutParams = layoutParamsVersion
|
|
||||||
|
|
||||||
binding.checkVersion.textSize = textSize
|
binding.exit.setOnClickListener{
|
||||||
val layoutParamsCheckVersion =
|
|
||||||
binding.checkVersion.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsCheckVersion.marginEnd = application.px2Px(binding.checkVersion.marginEnd)
|
|
||||||
binding.checkVersion.layoutParams = layoutParamsCheckVersion
|
|
||||||
|
|
||||||
binding.versionName.textSize = textSize
|
|
||||||
|
|
||||||
binding.clear.textSize = textSize
|
|
||||||
binding.exit.textSize = textSize
|
|
||||||
|
|
||||||
val layoutParamsChannelSwitch =
|
|
||||||
binding.switchChannelReversal.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParamsChannelSwitch.topMargin =
|
|
||||||
application.px2Px(binding.switchChannelReversal.marginTop)
|
|
||||||
|
|
||||||
binding.switchChannelReversal.textSize = textSize
|
|
||||||
binding.switchChannelReversal.layoutParams = layoutParamsChannelSwitch
|
|
||||||
|
|
||||||
binding.switchChannelNum.textSize = textSize
|
|
||||||
binding.switchChannelNum.layoutParams = layoutParamsChannelSwitch
|
|
||||||
|
|
||||||
binding.switchTime.textSize = textSize
|
|
||||||
binding.switchTime.layoutParams = layoutParamsChannelSwitch
|
|
||||||
|
|
||||||
binding.switchBootStartup.textSize = textSize
|
|
||||||
binding.switchBootStartup.layoutParams = layoutParamsChannelSwitch
|
|
||||||
|
|
||||||
binding.switchGrid.textSize = textSize
|
|
||||||
binding.switchGrid.layoutParams = layoutParamsChannelSwitch
|
|
||||||
|
|
||||||
binding.appreciate.layoutParams.width =
|
|
||||||
application.px2Px(binding.appreciate.layoutParams.width)
|
|
||||||
|
|
||||||
binding.exit.setOnClickListener {
|
|
||||||
requireActivity().finishAffinity()
|
requireActivity().finishAffinity()
|
||||||
}
|
}
|
||||||
|
|
||||||
// val myViewModel = application.myViewModel
|
|
||||||
// application.myViewModel.downloadProgress.observe(viewLifecycleOwner) { _ ->
|
|
||||||
// val downloadProgress = myViewModel.downloadProgress.value
|
|
||||||
// if (downloadProgress != null) {
|
|
||||||
// if (downloadProgress == 100) {
|
|
||||||
// binding.progressBar.visibility = GONE
|
|
||||||
// } else {
|
|
||||||
// if (!binding.progressBar.isVisible) {
|
|
||||||
// binding.progressBar.visibility = VISIBLE
|
|
||||||
// }
|
|
||||||
// binding.progressBar.progress = downloadProgress
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
updateManager = UpdateManager(context, context.appVersionCode)
|
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestInstallPermissions() {
|
fun setVersionName(versionName: String) {
|
||||||
val context = requireContext()
|
if (_binding != null) {
|
||||||
val permissionsList: MutableList<String> = ArrayList()
|
binding.versionName.text = versionName
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !context.packageManager.canRequestPackageInstalls()) {
|
|
||||||
permissionsList.add(Manifest.permission.REQUEST_INSTALL_PACKAGES)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
|
||||||
ContextCompat.checkSelfPermission(
|
|
||||||
context,
|
|
||||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
|
||||||
) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
|
||||||
ContextCompat.checkSelfPermission(
|
|
||||||
context,
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (permissionsList.isNotEmpty()) {
|
|
||||||
ActivityCompat.requestPermissions(
|
|
||||||
requireActivity(),
|
|
||||||
permissionsList.toTypedArray<String>(),
|
|
||||||
PERMISSIONS_REQUEST_CODE
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
updateManager.checkAndUpdate()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(
|
internal class OnClickListenerCheckVersion(
|
||||||
requestCode: Int,
|
private val mainActivity: MainActivity,
|
||||||
permissions: Array<out String>,
|
private val updateManager: UpdateManager
|
||||||
grantResults: IntArray
|
) :
|
||||||
) {
|
View.OnClickListener {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
override fun onClick(view: View?) {
|
||||||
if (requestCode == PERMISSIONS_REQUEST_CODE) {
|
mainActivity.settingDelayHide()
|
||||||
var allPermissionsGranted = true
|
updateManager.checkAndUpdate()
|
||||||
for (result in grantResults) {
|
|
||||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
allPermissionsGranted = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allPermissionsGranted) {
|
|
||||||
updateManager.checkAndUpdate()
|
|
||||||
} else {
|
|
||||||
Toast.makeText(context, "权限授权失败", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +110,6 @@ class SettingFragment : DialogFragment() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "SettingFragment"
|
const val TAG = "SettingFragment"
|
||||||
const val PERMISSIONS_REQUEST_CODE = 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-7
@@ -1,4 +1,4 @@
|
|||||||
package com.lizongying.mytv.models
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import com.lizongying.mytv.models.ProgramType
|
import com.lizongying.mytv.models.ProgramType
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
@@ -15,22 +15,18 @@ data class TV(
|
|||||||
var programType: ProgramType,
|
var programType: ProgramType,
|
||||||
var needToken: Boolean = false,
|
var needToken: Boolean = false,
|
||||||
var mustToken: Boolean = false,
|
var mustToken: Boolean = false,
|
||||||
var volume: Float = 0.1F,
|
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "TV{" +
|
return "TV{" +
|
||||||
"id=" + id +
|
"id=" + id +
|
||||||
", title='" + title + '\'' +
|
", title='" + title + '\'' +
|
||||||
", alias='" + alias + '\'' +
|
|
||||||
", videoUrl='" + videoUrl + '\'' +
|
", videoUrl='" + videoUrl + '\'' +
|
||||||
", channel='" + channel + '\'' +
|
|
||||||
", logo='" + logo + '\'' +
|
", logo='" + logo + '\'' +
|
||||||
", pid='" + pid + '\'' +
|
", pid='" + pid + '\'' +
|
||||||
", sid='" + sid + '\'' +
|
", sid='" + sid + '\'' +
|
||||||
", programType='" + programType + '\'' +
|
", programType='" + programType + '\'' +
|
||||||
", needToken='" + needToken + '\'' +
|
|
||||||
", mustToken='" + mustToken + '\'' +
|
|
||||||
'}'
|
'}'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+34
-67
@@ -1,6 +1,6 @@
|
|||||||
package com.lizongying.mytv.models
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import com.lizongying.mytv.R
|
import com.lizongying.mytv.models.ProgramType
|
||||||
|
|
||||||
object TVList {
|
object TVList {
|
||||||
val list: Map<String, List<TV>> by lazy {
|
val list: Map<String, List<TV>> by lazy {
|
||||||
@@ -21,8 +21,7 @@ object TVList {
|
|||||||
"2022576801",
|
"2022576801",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -35,8 +34,7 @@ object TVList {
|
|||||||
"2022576701",
|
"2022576701",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -49,8 +47,7 @@ object TVList {
|
|||||||
"2022576501",
|
"2022576501",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = true,
|
mustToken = true
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -63,8 +60,7 @@ object TVList {
|
|||||||
"2022576601",
|
"2022576601",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -77,8 +73,7 @@ object TVList {
|
|||||||
"2022576401",
|
"2022576401",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -91,8 +86,7 @@ object TVList {
|
|||||||
"2013693901",
|
"2013693901",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = true,
|
mustToken = true
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -105,8 +99,7 @@ object TVList {
|
|||||||
"2022576201",
|
"2022576201",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -119,8 +112,7 @@ object TVList {
|
|||||||
"2022576101",
|
"2022576101",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = true,
|
mustToken = true
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -133,8 +125,7 @@ object TVList {
|
|||||||
"2022576001",
|
"2022576001",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -147,8 +138,7 @@ object TVList {
|
|||||||
"2022573001",
|
"2022573001",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -161,8 +151,7 @@ object TVList {
|
|||||||
"2022575901",
|
"2022575901",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -175,8 +164,7 @@ object TVList {
|
|||||||
"2022575801",
|
"2022575801",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -189,8 +177,7 @@ object TVList {
|
|||||||
"2022575701",
|
"2022575701",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -203,8 +190,7 @@ object TVList {
|
|||||||
"2022575601",
|
"2022575601",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -217,8 +203,7 @@ object TVList {
|
|||||||
"2022575501",
|
"2022575501",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -231,8 +216,7 @@ object TVList {
|
|||||||
"2022575401",
|
"2022575401",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -245,8 +229,7 @@ object TVList {
|
|||||||
"2022575301",
|
"2022575301",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -259,8 +242,7 @@ object TVList {
|
|||||||
"2022576301",
|
"2022576301",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -273,8 +255,7 @@ object TVList {
|
|||||||
"2022575201",
|
"2022575201",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -287,8 +268,7 @@ object TVList {
|
|||||||
"2020603421",
|
"2020603421",
|
||||||
ProgramType.Y_JCE,
|
ProgramType.Y_JCE,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.8F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -758,8 +738,7 @@ object TVList {
|
|||||||
"2019927403",
|
"2019927403",
|
||||||
ProgramType.Y_JCE,
|
ProgramType.Y_JCE,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -772,8 +751,7 @@ object TVList {
|
|||||||
"2022606701",
|
"2022606701",
|
||||||
ProgramType.Y_JCE,
|
ProgramType.Y_JCE,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.8F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -786,8 +764,7 @@ object TVList {
|
|||||||
"2022823801",
|
"2022823801",
|
||||||
ProgramType.Y_JCE,
|
ProgramType.Y_JCE,
|
||||||
true,
|
true,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.6F
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"港澳台" to listOf(
|
"港澳台" to listOf(
|
||||||
@@ -802,8 +779,7 @@ object TVList {
|
|||||||
"",
|
"",
|
||||||
ProgramType.F,
|
ProgramType.F,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.7F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -816,8 +792,7 @@ object TVList {
|
|||||||
"",
|
"",
|
||||||
ProgramType.F,
|
ProgramType.F,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.7F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -830,8 +805,7 @@ object TVList {
|
|||||||
"",
|
"",
|
||||||
ProgramType.F,
|
ProgramType.F,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.7F
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"国际" to listOf(
|
"国际" to listOf(
|
||||||
@@ -846,8 +820,7 @@ object TVList {
|
|||||||
"2022575001",
|
"2022575001",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -860,8 +833,7 @@ object TVList {
|
|||||||
"2022574901",
|
"2022574901",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -874,8 +846,7 @@ object TVList {
|
|||||||
"2022574801",
|
"2022574801",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -888,8 +859,7 @@ object TVList {
|
|||||||
"2022574601",
|
"2022574601",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -902,8 +872,7 @@ object TVList {
|
|||||||
"2022571701",
|
"2022571701",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
TV(
|
TV(
|
||||||
0,
|
0,
|
||||||
@@ -916,8 +885,7 @@ object TVList {
|
|||||||
"2022574701",
|
"2022574701",
|
||||||
ProgramType.Y_PROTO,
|
ProgramType.Y_PROTO,
|
||||||
false,
|
false,
|
||||||
mustToken = false,
|
mustToken = false
|
||||||
0.5F
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -932,7 +900,6 @@ object TVList {
|
|||||||
v.forEach { v1 ->
|
v.forEach { v1 ->
|
||||||
if (!v1.mustToken) {
|
if (!v1.mustToken) {
|
||||||
v1.id = id
|
v1.id = id
|
||||||
v1.needToken = false
|
|
||||||
id++
|
id++
|
||||||
group.add(v1)
|
group.add(v1)
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,10 @@ package com.lizongying.mytv
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.marginEnd
|
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.lizongying.mytv.Utils.getDateFormat
|
import com.lizongying.mytv.Utils.getDateFormat
|
||||||
import com.lizongying.mytv.databinding.TimeBinding
|
import com.lizongying.mytv.databinding.TimeBinding
|
||||||
@@ -22,57 +21,74 @@ class TimeFragment : Fragment() {
|
|||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
|
Log.i(TAG, "onCreateView")
|
||||||
_binding = TimeBinding.inflate(inflater, container, false)
|
_binding = TimeBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
val application = requireActivity().applicationContext as MyTVApplication
|
val activity = requireActivity()
|
||||||
|
val application = activity.applicationContext as MyApplication
|
||||||
|
val displayMetrics = application.getDisplayMetrics()
|
||||||
|
|
||||||
binding.time.layoutParams.width = application.px2Px(binding.time.layoutParams.width)
|
displayMetrics.density
|
||||||
binding.time.layoutParams.height = application.px2Px(binding.time.layoutParams.height)
|
|
||||||
|
|
||||||
val layoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
|
var screenWidth = displayMetrics.widthPixels
|
||||||
layoutParams.topMargin = application.px2Px(binding.time.marginTop)
|
var screenHeight = displayMetrics.heightPixels
|
||||||
layoutParams.marginEnd = application.px2Px(binding.time.marginEnd)
|
if (screenHeight > screenWidth) {
|
||||||
binding.time.layoutParams = layoutParams
|
screenWidth = displayMetrics.heightPixels
|
||||||
|
screenHeight = displayMetrics.widthPixels
|
||||||
binding.content.textSize = application.px2PxFont(binding.content.textSize)
|
|
||||||
binding.channel.textSize = application.px2PxFont(binding.channel.textSize)
|
|
||||||
|
|
||||||
binding.main.layoutParams.width = application.shouldWidthPx()
|
|
||||||
binding.main.layoutParams.height = application.shouldHeightPx()
|
|
||||||
|
|
||||||
if (SP.time) {
|
|
||||||
handler.removeCallbacks(showRunnable)
|
|
||||||
handler.postDelayed(showRunnable, 0)
|
|
||||||
} else {
|
|
||||||
handler.removeCallbacks(showRunnable)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(activity as MainActivity).fragmentReady(TAG)
|
val ratio = 16f / 9f
|
||||||
|
|
||||||
|
if (screenWidth / screenHeight > ratio) {
|
||||||
|
val x = ((screenWidth - screenHeight * ratio) / 2).toInt()
|
||||||
|
val originalLayoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
originalLayoutParams.rightMargin += x
|
||||||
|
binding.time.layoutParams = originalLayoutParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screenWidth / screenHeight < ratio) {
|
||||||
|
val y = ((screenHeight - screenWidth / ratio) / 2).toInt()
|
||||||
|
val originalLayoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
originalLayoutParams.topMargin += y
|
||||||
|
binding.time.layoutParams = originalLayoutParams
|
||||||
|
}
|
||||||
|
|
||||||
|
(activity as MainActivity).fragmentReady("TimeFragment")
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onHiddenChanged(hidden: Boolean) {
|
override fun onResume() {
|
||||||
super.onHiddenChanged(hidden)
|
super.onResume()
|
||||||
if (!hidden) {
|
if (view?.visibility == View.VISIBLE) {
|
||||||
handler.removeCallbacks(showRunnable)
|
handler.removeCallbacks(showRunnable)
|
||||||
handler.postDelayed(showRunnable, 0)
|
handler.postDelayed(showRunnable, 0)
|
||||||
} else {
|
|
||||||
handler.removeCallbacks(showRunnable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
handler.removeCallbacks(showRunnable)
|
||||||
|
}
|
||||||
|
|
||||||
private val showRunnable: Runnable = Runnable {
|
private val showRunnable: Runnable = Runnable {
|
||||||
run {
|
run {
|
||||||
if (_binding == null) {
|
|
||||||
return@Runnable
|
|
||||||
}
|
|
||||||
binding.content.text = getDateFormat("HH:mm")
|
binding.content.text = getDateFormat("HH:mm")
|
||||||
handler.postDelayed(showRunnable, delay)
|
handler.postDelayed(showRunnable, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
fun show() {
|
||||||
|
view?.visibility = View.VISIBLE
|
||||||
handler.removeCallbacks(showRunnable)
|
handler.removeCallbacks(showRunnable)
|
||||||
|
handler.postDelayed(showRunnable, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide() {
|
||||||
|
view?.visibility = View.GONE
|
||||||
|
handler.removeCallbacks(showRunnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,206 @@
|
|||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.DownloadManager
|
||||||
|
import android.app.DownloadManager.Request
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.core.content.PermissionChecker
|
||||||
import androidx.work.WorkManager
|
import androidx.core.content.PermissionChecker.checkSelfPermission
|
||||||
import androidx.work.workDataOf
|
import com.lizongying.mytv.api.ReleaseV2
|
||||||
import com.lizongying.mytv.api.ApiClient
|
import com.lizongying.mytv.requests.MyRequest
|
||||||
import com.lizongying.mytv.requests.ReleaseRequest
|
|
||||||
import com.lizongying.mytv.requests.ReleaseResponse
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
class UpdateManager(
|
class UpdateManager(
|
||||||
private var context: Context,
|
private var context: Context,
|
||||||
|
private var settingFragment: SettingFragment,
|
||||||
private var versionCode: Long
|
private var versionCode: Long
|
||||||
) :
|
) :
|
||||||
ConfirmationFragment.ConfirmationListener {
|
ConfirmationFragment.ConfirmationListener {
|
||||||
|
|
||||||
private var releaseRequest = ReleaseRequest()
|
private var myRequest = MyRequest()
|
||||||
private var release: ReleaseResponse? = null
|
private var release: ReleaseV2? = null
|
||||||
|
|
||||||
|
private var downloadReceiver: DownloadReceiver? = null
|
||||||
|
|
||||||
fun checkAndUpdate() {
|
fun checkAndUpdate() {
|
||||||
|
if (!haveStoragePermission()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
var text = "版本获取失败"
|
var text = "版本获取失败"
|
||||||
var update = false
|
|
||||||
try {
|
try {
|
||||||
release = releaseRequest.getRelease()
|
release = myRequest.getRelease()
|
||||||
val code = release?.version_code
|
Log.i(TAG, "versionCode $versionCode ${release?.c}")
|
||||||
if (code != null) {
|
if (release?.c != null) {
|
||||||
if (code.toLong() >= versionCode) {
|
text = if (release?.c!! > versionCode) {
|
||||||
text = "最新版本:${release?.version_name}"
|
"最新版本:${release?.n}\n${release?.d ?: ""}"
|
||||||
update = true
|
|
||||||
} else {
|
} else {
|
||||||
text = "已是最新版本,不需要更新"
|
"已是最新版本,不需要更新"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error occurred: ${e.message}", e)
|
Log.e(TAG, "Error occurred: ${e.message}", e)
|
||||||
}
|
}
|
||||||
updateUI(text, update)
|
updateUI(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateUI(text: String, update: Boolean) {
|
private fun updateUI(text: String) {
|
||||||
val dialog = ConfirmationFragment(this@UpdateManager, text, update)
|
val dialog = ConfirmationFragment(this@UpdateManager, text)
|
||||||
dialog.show((context as FragmentActivity).supportFragmentManager, TAG)
|
dialog.show(settingFragment.fragmentManager, TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startDownload(context: Context, release: ReleaseResponse) {
|
private fun haveStoragePermission(): Boolean {
|
||||||
val versionName = release.version_name
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
val apkName = "my-tv"
|
if (checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
val apkFileName = "$apkName-${release.version_name}.apk"
|
=== PermissionChecker.PERMISSION_GRANTED
|
||||||
val downloadUrl =
|
) {
|
||||||
"${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk"
|
Log.e("Permission error", "You have permission")
|
||||||
Log.i(TAG, "downloadUrl: $downloadUrl")
|
return true
|
||||||
val downloadRequest = OneTimeWorkRequestBuilder<UpdateWorker>()
|
} else {
|
||||||
.setInputData(
|
Log.e("Permission error", "You have asked for permission")
|
||||||
workDataOf(
|
ActivityCompat.requestPermissions(
|
||||||
"VERSION_NAME" to versionName,
|
context as Activity, arrayOf(
|
||||||
"APK_FILENAME" to apkFileName,
|
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
"DOWNLOAD_URL" to downloadUrl
|
), 1
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else { //you don't need to worry about these stuff below api level 23
|
||||||
|
Log.e("Permission error", "You already have the permission")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun startDownload(release: ReleaseV2) {
|
||||||
|
val apkFileName = "my-tv-${release.n}.apk"
|
||||||
|
Log.i(TAG, "apkFileName $apkFileName")
|
||||||
|
val downloadManager =
|
||||||
|
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
val request = Request(Uri.parse(release.u))
|
||||||
|
Log.i(TAG, "url ${Uri.parse(release.u)}")
|
||||||
|
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()
|
||||||
|
request.setDestinationInExternalFilesDir(
|
||||||
|
context,
|
||||||
|
Environment.DIRECTORY_DOWNLOADS,
|
||||||
|
apkFileName
|
||||||
|
)
|
||||||
|
request.setTitle("${settingFragment.resources.getString(R.string.app_name)} ${release.n}")
|
||||||
|
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||||
|
request.setAllowedOverRoaming(false)
|
||||||
|
request.setMimeType("application/vnd.android.package-archive")
|
||||||
|
|
||||||
|
// 获取下载任务的引用
|
||||||
|
val downloadReference = downloadManager.enqueue(request)
|
||||||
|
|
||||||
|
downloadReceiver = DownloadReceiver(context, apkFileName, downloadReference)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
context.registerReceiver(
|
||||||
|
downloadReceiver,
|
||||||
|
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
|
||||||
|
Context.RECEIVER_NOT_EXPORTED,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
context.registerReceiver(
|
||||||
|
downloadReceiver,
|
||||||
|
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getDownloadProgress(context, downloadReference) { progress ->
|
||||||
|
println("Download progress: $progress%")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDownloadProgress(
|
||||||
|
context: Context,
|
||||||
|
downloadId: Long,
|
||||||
|
progressListener: (Int) -> Unit
|
||||||
|
) {
|
||||||
|
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
val intervalMillis: Long = 1000
|
||||||
|
|
||||||
|
handler.post(object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
Log.i(TAG, "search")
|
||||||
|
val query = DownloadManager.Query().setFilterById(downloadId)
|
||||||
|
val cursor: Cursor = downloadManager.query(query)
|
||||||
|
cursor.use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
val bytesDownloadedIndex =
|
||||||
|
it.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
|
||||||
|
val bytesTotalIndex =
|
||||||
|
it.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
|
||||||
|
|
||||||
|
// 检查列名是否存在
|
||||||
|
if (bytesDownloadedIndex != -1 && bytesTotalIndex != -1) {
|
||||||
|
val bytesDownloaded = it.getInt(bytesDownloadedIndex)
|
||||||
|
val bytesTotal = it.getInt(bytesTotalIndex)
|
||||||
|
|
||||||
|
if (bytesTotal != -1) {
|
||||||
|
val progress = (bytesDownloaded * 100L / bytesTotal).toInt()
|
||||||
|
progressListener(progress)
|
||||||
|
if (progress == 100) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handler.postDelayed(this, intervalMillis)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DownloadReceiver(
|
||||||
|
private val context: Context,
|
||||||
|
private val apkFileName: String,
|
||||||
|
private val downloadReference: Long
|
||||||
|
) : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
|
||||||
|
Log.i(TAG, "reference $reference")
|
||||||
|
val progress = intent.getIntExtra("progress", 0)
|
||||||
|
Log.i(TAG, "progress $progress")
|
||||||
|
|
||||||
|
// 检查是否是我们发起的下载
|
||||||
|
if (reference == downloadReference) {
|
||||||
|
// 下载完成,触发安装
|
||||||
|
installNewVersion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun installNewVersion() {
|
||||||
|
val installIntent = Intent(Intent.ACTION_VIEW)
|
||||||
|
val apkUri = Uri.fromFile(
|
||||||
|
File(
|
||||||
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
||||||
|
apkFileName
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.build()
|
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive")
|
||||||
|
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
WorkManager.getInstance(context).enqueue(downloadRequest)
|
context.startActivity(installIntent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -76,9 +209,16 @@ class UpdateManager(
|
|||||||
|
|
||||||
override fun onConfirm() {
|
override fun onConfirm() {
|
||||||
Log.i(TAG, "onConfirm $release")
|
Log.i(TAG, "onConfirm $release")
|
||||||
release?.let { startDownload(context, it) }
|
release?.let { startDownload(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCancel() {
|
override fun onCancel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun destroy() {
|
||||||
|
if (downloadReceiver != null) {
|
||||||
|
context.unregisterReceiver(downloadReceiver)
|
||||||
|
Log.i(TAG, "destroy downloadReceiver")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.app.DownloadManager
|
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Environment
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import androidx.work.CoroutineWorker
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import com.lizongying.mytv.models.MyViewModel
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class UpdateWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
|
||||||
|
|
||||||
private lateinit var notificationManager: NotificationManager
|
|
||||||
private lateinit var notificationBuilder: NotificationCompat.Builder
|
|
||||||
|
|
||||||
private lateinit var myViewModel: MyViewModel
|
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
|
||||||
val downloadUrl = inputData.getString("DOWNLOAD_URL") ?: return Result.failure()
|
|
||||||
val apkFileName = inputData.getString("APK_FILENAME") ?: return Result.failure()
|
|
||||||
val versionName = inputData.getString("VERSION_NAME") ?: return Result.failure()
|
|
||||||
|
|
||||||
showNotification(applicationContext)
|
|
||||||
|
|
||||||
val app = applicationContext as MyTVApplication
|
|
||||||
myViewModel = app.myViewModel
|
|
||||||
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
downloadAndInstall(applicationContext, downloadUrl, apkFileName, versionName)
|
|
||||||
Result.success()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Result.failure()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNotification(context: Context) {
|
|
||||||
notificationManager =
|
|
||||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
notificationBuilder = NotificationCompat.Builder(context, "download_channel").apply {
|
|
||||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
|
||||||
setContentTitle("Downloading Update")
|
|
||||||
setContentText("Download in progress")
|
|
||||||
priority = NotificationCompat.PRIORITY_LOW
|
|
||||||
setOngoing(true)
|
|
||||||
setProgress(100, 0, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val channel = NotificationChannel(
|
|
||||||
"download_channel",
|
|
||||||
"Download Updates",
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
)
|
|
||||||
notificationManager.createNotificationChannel(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
notificationManager.notify(1, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun downloadAndInstall(
|
|
||||||
context: Context,
|
|
||||||
downloadUrl: String,
|
|
||||||
apkFileName: String,
|
|
||||||
versionName: String
|
|
||||||
) {
|
|
||||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()
|
|
||||||
Log.i(TAG, "save dir ${Environment.DIRECTORY_DOWNLOADS}")
|
|
||||||
val request = DownloadManager.Request(Uri.parse(downloadUrl)).apply {
|
|
||||||
setTitle("${context.resources.getString(R.string.app_name)} $versionName Downloading")
|
|
||||||
setDescription("Downloading the latest version of the app")
|
|
||||||
setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, apkFileName)
|
|
||||||
|
|
||||||
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
|
||||||
// setAllowedOverRoaming(false)
|
|
||||||
setMimeType("application/vnd.android.package-archive")
|
|
||||||
}
|
|
||||||
|
|
||||||
val manager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
|
||||||
val downloadId = manager.enqueue(request)
|
|
||||||
|
|
||||||
var downloading = true
|
|
||||||
while (downloading) {
|
|
||||||
val query = DownloadManager.Query().setFilterById(downloadId)
|
|
||||||
val cursor = manager.query(query)
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
val bytesDownloaded =
|
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
|
|
||||||
val bytesTotal =
|
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
|
|
||||||
|
|
||||||
if (bytesTotal > 0) {
|
|
||||||
val progress = (bytesDownloaded * 100L / bytesTotal).toInt()
|
|
||||||
Log.i(TAG, "progress $progress")
|
|
||||||
// myViewModel.setDownloadProgress(progress)
|
|
||||||
notificationBuilder.setProgress(100, progress, false)
|
|
||||||
notificationManager.notify(1, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
when (cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))) {
|
|
||||||
DownloadManager.STATUS_SUCCESSFUL -> downloading = false
|
|
||||||
DownloadManager.STATUS_FAILED -> {
|
|
||||||
downloading = false
|
|
||||||
throw Exception("Download failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
notificationBuilder.setContentText("Download complete")
|
|
||||||
.setProgress(0, 0, false)
|
|
||||||
.setOngoing(false)
|
|
||||||
notificationManager.notify(1, notificationBuilder.build())
|
|
||||||
|
|
||||||
val apkFile = File(
|
|
||||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
|
||||||
apkFileName
|
|
||||||
)
|
|
||||||
|
|
||||||
if (apkFile.exists()) {
|
|
||||||
val apkUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
FileProvider.getUriForFile(context, context.packageName + ".fileprovider", apkFile)
|
|
||||||
.apply {
|
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Uri.parse("file://${apkFile.absolutePath}")
|
|
||||||
// Uri.fromFile(apkFile)
|
|
||||||
}
|
|
||||||
// val apkUri = Uri.parse("file://$apkFile")
|
|
||||||
Log.i(TAG, "apkUri $apkUri")
|
|
||||||
val installIntent = Intent(Intent.ACTION_VIEW).apply {
|
|
||||||
setDataAndType(apkUri, "application/vnd.android.package-archive")
|
|
||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
context.startActivity(installIntent)
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "APK file does not exist!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "UpdateWorker"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,11 +5,8 @@ import android.os.Build
|
|||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.lizongying.mytv.api.TimeResponse
|
import com.lizongying.mytv.api.TimeResponse
|
||||||
import com.lizongying.mytv.requests.Request
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.Response
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@@ -18,8 +15,6 @@ import java.util.Locale
|
|||||||
object Utils {
|
object Utils {
|
||||||
private var between: Long = 0
|
private var between: Long = 0
|
||||||
|
|
||||||
private var listener: Request.RequestListener? = null
|
|
||||||
|
|
||||||
fun getDateFormat(format: String): String {
|
fun getDateFormat(format: String): String {
|
||||||
return SimpleDateFormat(
|
return SimpleDateFormat(
|
||||||
format,
|
format,
|
||||||
@@ -36,32 +31,13 @@ object Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun init() {
|
suspend fun init() {
|
||||||
|
var currentTimeMillis: Long = 0
|
||||||
try {
|
try {
|
||||||
val currentTimeMillis = getTimestampFromServer()
|
currentTimeMillis = getTimestampFromServer()
|
||||||
if (currentTimeMillis > 0) {
|
|
||||||
between = System.currentTimeMillis() - currentTimeMillis
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("Failed to retrieve timestamp from server: ${e.message}")
|
println("Failed to retrieve timestamp from server: ${e.message}")
|
||||||
}
|
}
|
||||||
|
between = System.currentTimeMillis() - currentTimeMillis
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
listener?.onRequestFinished(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RetryInterceptor(private val maxRetry: Int) : Interceptor {
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
|
||||||
val request = chain.request()
|
|
||||||
var response = chain.proceed(request)
|
|
||||||
var tryCount = 0
|
|
||||||
while (!response.isSuccessful && tryCount < maxRetry) {
|
|
||||||
tryCount++
|
|
||||||
response = chain.proceed(request)
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,8 +47,8 @@ object Utils {
|
|||||||
private suspend fun getTimestampFromServer(): Long {
|
private suspend fun getTimestampFromServer(): Long {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val client = okhttp3.OkHttpClient.Builder()
|
val client = okhttp3.OkHttpClient.Builder()
|
||||||
.addInterceptor(RetryInterceptor(3))
|
.connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
|
||||||
.build()
|
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build()
|
||||||
val request = okhttp3.Request.Builder()
|
val request = okhttp3.Request.Builder()
|
||||||
.url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp")
|
.url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp")
|
||||||
.build()
|
.build()
|
||||||
@@ -83,6 +59,7 @@ object Utils {
|
|||||||
Gson().fromJson(string, TimeResponse::class.java).data.t.toLong()
|
Gson().fromJson(string, TimeResponse::class.java).data.t.toLong()
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
// Handle network errors
|
||||||
throw IOException("Error during network request", e)
|
throw IOException("Error during network request", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,8 +72,6 @@ object Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dpToPx(dp: Int): Int {
|
fun dpToPx(dp: Int): Int {
|
||||||
// val density = Resources.getSystem().displayMetrics.density
|
|
||||||
// return (dp * density + 0.5f).toInt()
|
|
||||||
return TypedValue.applyDimension(
|
return TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), Resources.getSystem().displayMetrics
|
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), Resources.getSystem().displayMetrics
|
||||||
).toInt()
|
).toInt()
|
||||||
@@ -113,8 +88,4 @@ object Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isTmallDevice() = Build.MANUFACTURER.equals("Tmall", ignoreCase = true)
|
fun isTmallDevice() = Build.MANUFACTURER.equals("Tmall", ignoreCase = true)
|
||||||
|
|
||||||
fun setRequestListener(listener: Request.RequestListener) {
|
|
||||||
this.listener = listener
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,7 @@ package com.lizongying.mytv.api
|
|||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.lizongying.mytv.jce.JceConverterFactory
|
import com.lizongying.mytv.jce.JceConverterFactory
|
||||||
import com.lizongying.mytv.requests.ReleaseService
|
|
||||||
import okhttp3.ConnectionSpec
|
import okhttp3.ConnectionSpec
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.TlsVersion
|
import okhttp3.TlsVersion
|
||||||
@@ -25,19 +23,17 @@ class ApiClient {
|
|||||||
private val protoUrl = "https://capi.yangshipin.cn/"
|
private val protoUrl = "https://capi.yangshipin.cn/"
|
||||||
private val traceUrl = "https://btrace.yangshipin.cn/"
|
private val traceUrl = "https://btrace.yangshipin.cn/"
|
||||||
private val trace2Url = "https://aatc-api.yangshipin.cn/"
|
private val trace2Url = "https://aatc-api.yangshipin.cn/"
|
||||||
private val tokenUrl = "https://h5access.yangshipin.cn/"
|
|
||||||
private val trace3Url = "https://dtrace.ysp.cctv.cn/"
|
private val trace3Url = "https://dtrace.ysp.cctv.cn/"
|
||||||
private val jceUrl = "https://jacc.ysp.cctv.cn/"
|
private val jceUrl = "https://jacc.ysp.cctv.cn/"
|
||||||
private val fUrl = "https://m.fengshows.com/"
|
private val fUrl = "https://m.fengshows.com/"
|
||||||
|
|
||||||
private var okHttpClient = getUnsafeOkHttpClient()
|
private var okHttpClient = getUnsafeOkHttpClient()
|
||||||
private var gson = Gson()
|
|
||||||
|
|
||||||
val yspApiService: YSPApiService by lazy {
|
val yspApiService: YSPApiService by lazy {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(yspUrl)
|
.baseUrl(yspUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPApiService::class.java)
|
.build().create(YSPApiService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,15 +41,15 @@ class ApiClient {
|
|||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(myUrl)
|
.baseUrl(myUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPTokenService::class.java)
|
.build().create(YSPTokenService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
val releaseService: ReleaseService by lazy {
|
val releaseService: ReleaseService by lazy {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(HOST)
|
.baseUrl(myUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(ReleaseService::class.java)
|
.build().create(ReleaseService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +65,7 @@ class ApiClient {
|
|||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(traceUrl)
|
.baseUrl(traceUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPBtraceService::class.java)
|
.build().create(YSPBtraceService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,23 +73,15 @@ class ApiClient {
|
|||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(trace2Url)
|
.baseUrl(trace2Url)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPBtraceService::class.java)
|
.build().create(YSPBtraceService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
val yspToken2Service: YSPApiService by lazy {
|
|
||||||
Retrofit.Builder()
|
|
||||||
.baseUrl(tokenUrl)
|
|
||||||
.client(okHttpClient)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.build().create(YSPApiService::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
val yspBtraceService3: YSPBtraceService by lazy {
|
val yspBtraceService3: YSPBtraceService by lazy {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(trace3Url)
|
.baseUrl(trace3Url)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPBtraceService::class.java)
|
.build().create(YSPBtraceService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +97,7 @@ class ApiClient {
|
|||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(fUrl)
|
.baseUrl(fUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(FAuthService::class.java)
|
.build().create(FAuthService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,9 +170,4 @@ class ApiClient {
|
|||||||
throw RuntimeException(e)
|
throw RuntimeException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val HOST = "https://gitee.com/lizongying/my-tv/raw/"
|
|
||||||
const val DOWNLOAD_HOST = "https://gitee.com/lizongying/my-tv/releases/download/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package com.lizongying.mytv.api
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
data class KvcollectRequest(
|
data class KvcollectRequest(
|
||||||
val BossId: Int = 99150,
|
val BossId: Int = 2727,
|
||||||
val Pwd: Int = 1999332929,
|
val Pwd: Int = 1424084450,
|
||||||
val cdn: String = "waibao",
|
val cdn: String = "waibao",
|
||||||
val cmd: Int = 263,
|
val cmd: Int = 263,
|
||||||
val defn: String = "fhd",
|
val defn: String = "fhd",
|
||||||
val downspeed: Int = 10,
|
val downspeed: Double = 10.0,
|
||||||
val durl: String = "", //
|
val durl: String = "", //
|
||||||
val errcode: String = "",
|
val errcode: String = "",
|
||||||
val fact1: String = "ysp_pc_live_b",
|
val fact1: String = "ysp_pc_live_b",
|
||||||
val firstreport: Int = 0,
|
val firstreport: Int = 0,
|
||||||
val fplayerver: String = "180",
|
val fplayerver: String = "100",
|
||||||
val ftime: String = "", //
|
val ftime: String = "", //
|
||||||
val geturltime: Int = 0,
|
val geturltime: Int = 0,
|
||||||
val guid: String = "", //
|
val guid: String = "", //
|
||||||
@@ -39,17 +39,17 @@ data class KvcollectRequest(
|
|||||||
|
|
||||||
|
|
||||||
data class KvcollectRequest2(
|
data class KvcollectRequest2(
|
||||||
val BossId: Int = 99150,
|
val BossId: Int = 2727,
|
||||||
val Pwd: Int = 1999332929,
|
val Pwd: Int = 1424084450,
|
||||||
val cdn: String = "waibao",
|
val cdn: String = "waibao",
|
||||||
val cmd: Int = 263,
|
val cmd: Int = 263,
|
||||||
val defn: String = "fhd",
|
val defn: String = "fhd",
|
||||||
val downspeed: Int = 10,
|
val downspeed: String = "10",
|
||||||
val durl: String = "", //
|
val durl: String = "", //
|
||||||
val errcode: String = "",
|
val errcode: String = "",
|
||||||
val fact1: String = "ysp_pc_live_b",
|
val fact1: String = "ysp_pc_live_b",
|
||||||
val firstreport: Int = 0,
|
val firstreport: Int = 0,
|
||||||
val fplayerver: String = "180",
|
val fplayerver: String = "100",
|
||||||
val ftime: String = "", //
|
val ftime: String = "", //
|
||||||
val geturltime: Int = 0,
|
val geturltime: Int = 0,
|
||||||
val guid: String = "", //
|
val guid: String = "", //
|
||||||
@@ -68,9 +68,9 @@ data class KvcollectRequest2(
|
|||||||
val sRef: String = "",
|
val sRef: String = "",
|
||||||
val sUrl: String = "", //
|
val sUrl: String = "", //
|
||||||
val sdtfrom: String = "ysp_pc_01",
|
val sdtfrom: String = "ysp_pc_01",
|
||||||
val seq: Int = 0, //
|
val seq: Int = 9, //
|
||||||
var signature: String = "",
|
var signature: String = "",
|
||||||
val url: String = "", //
|
val url: String = "", //
|
||||||
val viewid: String = "", //
|
val viewid: String = "", //
|
||||||
val _dc: String = "",
|
val _dc: Double = 0.0,
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Path
|
||||||
|
|
||||||
|
interface ReleaseService {
|
||||||
|
@GET("my-tv/v2/release/{name}")
|
||||||
|
fun getRelease(
|
||||||
|
@Path("name") date: String = "1",
|
||||||
|
): Call<ReleaseV2>
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.lizongying.mytv.api
|
|
||||||
|
|
||||||
data class Token2(
|
|
||||||
val ret: Int?,
|
|
||||||
val msg: String?,
|
|
||||||
val data: Data,
|
|
||||||
) {
|
|
||||||
data class Data(
|
|
||||||
val token: String,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.lizongying.mytv.api
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import com.lizongying.mytv.Encryptor
|
||||||
import com.lizongying.mytv.SP
|
import com.lizongying.mytv.SP
|
||||||
import com.lizongying.mytv.Utils.getDateTimestamp
|
import com.lizongying.mytv.Utils.getDateTimestamp
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
import java.security.MessageDigest
|
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@@ -54,14 +53,6 @@ object YSP {
|
|||||||
|
|
||||||
private var appid = "ysp_pc"
|
private var appid = "ysp_pc"
|
||||||
var token = ""
|
var token = ""
|
||||||
var token2 = ""
|
|
||||||
|
|
||||||
var yspsdkinput = ""
|
|
||||||
var openapi_signature = ""
|
|
||||||
var yspticket = ""
|
|
||||||
|
|
||||||
var nseqId = 1
|
|
||||||
var nrequest_id = ""
|
|
||||||
|
|
||||||
private var encryptor = Encryptor()
|
private var encryptor = Encryptor()
|
||||||
|
|
||||||
@@ -85,45 +76,10 @@ object YSP {
|
|||||||
|
|
||||||
cKey =
|
cKey =
|
||||||
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform)
|
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform)
|
||||||
randStr = getRand()
|
|
||||||
signature = getSignature()
|
signature = getSignature()
|
||||||
yspticket = encryptor.encrypt2("$livepid&$timeStr&$guid&519748109").lowercase()
|
|
||||||
|
|
||||||
return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}"""
|
return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}"""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTokenData(tvModel: TVViewModel) {
|
|
||||||
livepid = tvModel.getTV().pid
|
|
||||||
cnlid = tvModel.getTV().sid
|
|
||||||
defn = "fhd"
|
|
||||||
|
|
||||||
randStr = getRand()
|
|
||||||
|
|
||||||
if (tvModel.retryTimes > 0) {
|
|
||||||
guid = newGuid()
|
|
||||||
}
|
|
||||||
|
|
||||||
cKey =
|
|
||||||
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform)
|
|
||||||
|
|
||||||
yspsdkinput =
|
|
||||||
md("adjust=$adjust&app_version=$appVersion&appVer=$appVer&channel=$channel&cKey=$cKey&cmd=$cmd&cnlid=$cnlid&defn=$defn&devid=$devid&dtype=$dtype&encryptVer=$encryptVer&guid=$guid&livepid=$livepid&otype=$otype&platform=$platform&sphttps=$sphttps&stream=$stream")
|
|
||||||
|
|
||||||
nseqId++
|
|
||||||
|
|
||||||
nrequest_id = "999999" + getRand() + getTimeStr()
|
|
||||||
|
|
||||||
openapi_signature =
|
|
||||||
md("yspappid:519748109;host:www.yangshipin.cn;protocol:https:;token:$token2;input:$yspsdkinput-$guid-$nseqId-$nrequest_id;")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun md(str: String): String {
|
|
||||||
val md = MessageDigest.getInstance("MD5")
|
|
||||||
md.update(str.toByteArray())
|
|
||||||
val digest = md.digest()
|
|
||||||
return digest.let { it -> it.joinToString("") { "%02x".format(it) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAuthData(tvModel: TVViewModel): String {
|
fun getAuthData(tvModel: TVViewModel): String {
|
||||||
livepid = tvModel.getTV().pid
|
livepid = tvModel.getTV().pid
|
||||||
|
|
||||||
@@ -137,7 +93,7 @@ object YSP {
|
|||||||
return """pid=$livepid&guid=$guid&appid=$appid&rand_str=$randStr&signature=$signature"""
|
return """pid=$livepid&guid=$guid&appid=$appid&rand_str=$randStr&signature=$signature"""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTimeStr(): String {
|
private fun getTimeStr(): String {
|
||||||
return getDateTimestamp().toString()
|
return getDateTimestamp().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +107,6 @@ object YSP {
|
|||||||
var guid = SP.guid
|
var guid = SP.guid
|
||||||
if (guid.length < 18) {
|
if (guid.length < 18) {
|
||||||
guid = generateGuid()
|
guid = generateGuid()
|
||||||
this.guid = guid
|
|
||||||
SP.guid = guid
|
SP.guid = guid
|
||||||
}
|
}
|
||||||
return guid
|
return guid
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ package com.lizongying.mytv.api
|
|||||||
|
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
import retrofit2.http.Headers
|
import retrofit2.http.Headers
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Query
|
|
||||||
|
|
||||||
|
|
||||||
interface YSPApiService {
|
interface YSPApiService {
|
||||||
@@ -20,12 +18,6 @@ interface YSPApiService {
|
|||||||
fun getLiveInfo(
|
fun getLiveInfo(
|
||||||
@Header("cookie") cookie: String,
|
@Header("cookie") cookie: String,
|
||||||
@Header("Yspplayertoken") token: String,
|
@Header("Yspplayertoken") token: String,
|
||||||
@Header("Yspsdkinput") Yspsdkinput: String,
|
|
||||||
@Header("yspsdksign") yspsdksign: String,
|
|
||||||
@Header("Yspticket") Yspticket: String,
|
|
||||||
@Header("Seqid") Seqid: String,
|
|
||||||
@Header("Request-Id") RequestId: String,
|
|
||||||
@Header("Yspappid") Yspappid: String="519748109",
|
|
||||||
@Body request: LiveInfoRequest,
|
@Body request: LiveInfoRequest,
|
||||||
): Call<LiveInfo>
|
): Call<LiveInfo>
|
||||||
|
|
||||||
@@ -40,20 +32,4 @@ interface YSPApiService {
|
|||||||
@Header("cookie") cookie: String,
|
@Header("cookie") cookie: String,
|
||||||
@Body request: AuthRequest,
|
@Body request: AuthRequest,
|
||||||
): Call<Auth>
|
): Call<Auth>
|
||||||
|
|
||||||
@GET("web/open/token")
|
|
||||||
@Headers(
|
|
||||||
"content-type: application/json",
|
|
||||||
"referer: https://www.yangshipin.cn/",
|
|
||||||
"user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
||||||
)
|
|
||||||
fun getToken(
|
|
||||||
@Header("cookie") cookie: String,
|
|
||||||
@Query("yspappid") yspappid: String = "519748109",
|
|
||||||
@Query("guid") guid: String = "",
|
|
||||||
@Query("vappid") vappid: String = "59306155",
|
|
||||||
@Query("vsecret") vsecret: String = "b42702bf7309a179d102f3d51b1add2fda0bc7ada64cb801",
|
|
||||||
@Query("raw") raw: String = "1",
|
|
||||||
@Query("ts") ts: String = "",
|
|
||||||
): Call<Token2>
|
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,8 @@ interface YSPBtraceService {
|
|||||||
"referer: https://www.yangshipin.cn/",
|
"referer: https://www.yangshipin.cn/",
|
||||||
)
|
)
|
||||||
fun kvcollect3(
|
fun kvcollect3(
|
||||||
@Field("BossId") BossId: String = "9150",
|
@Field("BossId") BossId: String = "9141",
|
||||||
@Field("Pwd") Pwd: String = "1999332929",
|
@Field("Pwd") Pwd: String = "1137850982",
|
||||||
@Field("prog") prog: String = "", //
|
@Field("prog") prog: String = "", //
|
||||||
@Field("playno") playno: String = "", //
|
@Field("playno") playno: String = "", //
|
||||||
@Field("guid") guid: String = "", //
|
@Field("guid") guid: String = "", //
|
||||||
@@ -102,7 +102,7 @@ interface YSPBtraceService {
|
|||||||
@Field("firstreport") firstreport: String = "-",
|
@Field("firstreport") firstreport: String = "-",
|
||||||
@Field("sUrl") sUrl: String = "", //
|
@Field("sUrl") sUrl: String = "", //
|
||||||
@Field("sRef") sRef: String = "-",
|
@Field("sRef") sRef: String = "-",
|
||||||
@Field("fplayerver") fplayerver: String = "180",
|
@Field("fplayerver") fplayerver: String = "100",
|
||||||
@Field("livepid") livepid: String = "",
|
@Field("livepid") livepid: String = "",
|
||||||
@Field("viewid") viewid: String = "",
|
@Field("viewid") viewid: String = "",
|
||||||
@Field("seq") seq: String = "",
|
@Field("seq") seq: String = "",
|
||||||
@@ -118,8 +118,8 @@ interface YSPBtraceService {
|
|||||||
@Field("_dc") _dc: String = "",
|
@Field("_dc") _dc: String = "",
|
||||||
@Field("live_type") live_type: String = "-",
|
@Field("live_type") live_type: String = "-",
|
||||||
@Field("ftime") ftime: String = "",
|
@Field("ftime") ftime: String = "",
|
||||||
// @Field("url") url: String = "",
|
@Field("url") url: String = "",
|
||||||
// @Field("rand_str") rand_str: String = "", //
|
@Field("rand_str") rand_str: String = "", //
|
||||||
// @Field("signature") signature: String = "",
|
@Field("signature") signature: String = "",
|
||||||
): Call<Void>
|
): Call<Void>
|
||||||
}
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.lizongying.mytv.models
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
|
|
||||||
class MyViewModel : ViewModel() {
|
|
||||||
private var _downloadProgress = MutableLiveData<Int>()
|
|
||||||
val downloadProgress: LiveData<Int>
|
|
||||||
get() = _downloadProgress
|
|
||||||
|
|
||||||
fun setDownloadProgress(progress: Int) {
|
|
||||||
_downloadProgress.value = progress
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
_downloadProgress.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package com.lizongying.mytv.models
|
|||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.lizongying.mytv.SP
|
|
||||||
|
|
||||||
class TVListViewModel : ViewModel() {
|
class TVListViewModel : ViewModel() {
|
||||||
|
|
||||||
@@ -17,6 +16,10 @@ class TVListViewModel : ViewModel() {
|
|||||||
val itemPosition: LiveData<Int>
|
val itemPosition: LiveData<Int>
|
||||||
get() = _itemPosition
|
get() = _itemPosition
|
||||||
|
|
||||||
|
private val _itemPositionCurrent = MutableLiveData<Int>()
|
||||||
|
val itemPositionCurrent: LiveData<Int>
|
||||||
|
get() = _itemPositionCurrent
|
||||||
|
|
||||||
fun addTVViewModel(tvViewModel: TVViewModel) {
|
fun addTVViewModel(tvViewModel: TVViewModel) {
|
||||||
if (_tvListViewModel.value == null) {
|
if (_tvListViewModel.value == null) {
|
||||||
_tvListViewModel.value = mutableListOf(tvViewModel)
|
_tvListViewModel.value = mutableListOf(tvViewModel)
|
||||||
@@ -29,16 +32,23 @@ class TVListViewModel : ViewModel() {
|
|||||||
return _tvListViewModel.value?.get(id)
|
return _tvListViewModel.value?.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getTVViewModelCurrent(): TVViewModel? {
|
||||||
|
return _itemPositionCurrent.value?.let { _tvListViewModel.value?.get(it) }
|
||||||
|
}
|
||||||
|
|
||||||
fun setItemPosition(position: Int) {
|
fun setItemPosition(position: Int) {
|
||||||
_itemPosition.value = position
|
_itemPosition.value = position
|
||||||
SP.itemPosition = position
|
_itemPositionCurrent.value = position
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItemPositionCurrent(position: Int) {
|
||||||
|
_itemPositionCurrent.value = position
|
||||||
}
|
}
|
||||||
|
|
||||||
fun size(): Int {
|
fun size(): Int {
|
||||||
if (_tvListViewModel.value == null) {
|
if (_tvListViewModel.value == null) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return _tvListViewModel.value!!.size
|
return _tvListViewModel.value!!.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.lizongying.mytv.models
|
package com.lizongying.mytv.models
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.lizongying.mytv.TV
|
||||||
import com.lizongying.mytv.api.FEPG
|
import com.lizongying.mytv.api.FEPG
|
||||||
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program
|
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program
|
||||||
import com.tencent.videolite.android.datamodel.cctvjce.TVProgram
|
import com.tencent.videolite.android.datamodel.cctvjce.TVProgram
|
||||||
@@ -16,8 +18,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
|
|
||||||
var retryTimes = 0
|
var retryTimes = 0
|
||||||
var retryMaxTimes = 8
|
var retryMaxTimes = 8
|
||||||
var authYSPRetryTimes = 0
|
|
||||||
var authYSPRetryMaxTimes = 3
|
|
||||||
var tokenYSPRetryTimes = 0
|
var tokenYSPRetryTimes = 0
|
||||||
var tokenYSPRetryMaxTimes = 0
|
var tokenYSPRetryMaxTimes = 0
|
||||||
var tokenFHRetryTimes = 0
|
var tokenFHRetryTimes = 0
|
||||||
@@ -41,8 +41,8 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
val videoIndex: LiveData<Int>
|
val videoIndex: LiveData<Int>
|
||||||
get() = _videoIndex
|
get() = _videoIndex
|
||||||
|
|
||||||
private val _change = MutableLiveData<String>()
|
private val _change = MutableLiveData<Boolean>()
|
||||||
val change: LiveData<String>
|
val change: LiveData<Boolean>
|
||||||
get() = _change
|
get() = _change
|
||||||
|
|
||||||
private val _ready = MutableLiveData<Boolean>()
|
private val _ready = MutableLiveData<Boolean>()
|
||||||
@@ -56,27 +56,36 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
if (_videoUrl.value!!.last().contains("cctv.cn")) {
|
if (_videoUrl.value!!.last().contains("cctv.cn")) {
|
||||||
tv.videoUrl = tv.videoUrl.subList(0, tv.videoUrl.lastIndex) + listOf(url)
|
tv.videoUrl = tv.videoUrl.subList(0, tv.videoUrl.lastIndex) + listOf(url)
|
||||||
} else {
|
} else {
|
||||||
tv.videoUrl += listOf(url)
|
tv.videoUrl = tv.videoUrl + listOf(url)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tv.videoUrl += listOf(url)
|
tv.videoUrl = tv.videoUrl + listOf(url)
|
||||||
}
|
}
|
||||||
_videoUrl.value = tv.videoUrl
|
_videoUrl.value = tv.videoUrl
|
||||||
_videoIndex.value = tv.videoUrl.lastIndex
|
_videoIndex.value = tv.videoUrl.lastIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changed(from: String) {
|
fun firstSource() {
|
||||||
retryTimes = 0
|
if (_videoUrl.value!!.isNotEmpty()) {
|
||||||
authYSPRetryTimes = 0
|
setVideoIndex(0)
|
||||||
tokenYSPRetryTimes = 0
|
allReady()
|
||||||
tokenFHRetryTimes = 0
|
} else {
|
||||||
_change.value = from
|
Log.e(TAG, "no first")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changed() {
|
||||||
|
_change.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allReady() {
|
fun allReady() {
|
||||||
_ready.value = true
|
_ready.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setVideoIndex(videoIndex: Int) {
|
||||||
|
_videoIndex.value = videoIndex
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
_videoUrl.value = tv.videoUrl
|
_videoUrl.value = tv.videoUrl
|
||||||
_videoIndex.value = tv.videoUrl.lastIndex
|
_videoIndex.value = tv.videoUrl.lastIndex
|
||||||
|
|||||||
+7
-10
@@ -10,23 +10,20 @@ import retrofit2.Response
|
|||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
class ReleaseRequest {
|
class MyRequest {
|
||||||
private var releaseService = ApiClient().releaseService
|
private var releaseService = ApiClient().releaseService
|
||||||
|
|
||||||
suspend fun getRelease(): ReleaseResponse? {
|
suspend fun getRelease(): ReleaseV2? {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
fetchRelease()
|
fetchRelease()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchRelease(): ReleaseResponse? {
|
private suspend fun fetchRelease(): ReleaseV2? {
|
||||||
return suspendCoroutine { continuation ->
|
return suspendCoroutine { continuation ->
|
||||||
releaseService.getRelease()
|
releaseService.getRelease()
|
||||||
.enqueue(object : Callback<ReleaseResponse> {
|
.enqueue(object : Callback<ReleaseV2> {
|
||||||
override fun onResponse(
|
override fun onResponse(call: Call<ReleaseV2>, response: Response<ReleaseV2>) {
|
||||||
call: Call<ReleaseResponse>,
|
|
||||||
response: Response<ReleaseResponse>
|
|
||||||
) {
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
continuation.resume(response.body())
|
continuation.resume(response.body())
|
||||||
} else {
|
} else {
|
||||||
@@ -34,7 +31,7 @@ class ReleaseRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<ReleaseResponse>, t: Throwable) {
|
override fun onFailure(call: Call<ReleaseV2>, t: Throwable) {
|
||||||
continuation.resume(null)
|
continuation.resume(null)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -42,6 +39,6 @@ class ReleaseRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ReleaseRequest"
|
private const val TAG = "MyRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.lizongying.mytv.requests
|
|
||||||
|
|
||||||
|
|
||||||
data class ReleaseResponse(
|
|
||||||
val version_code: Int?,
|
|
||||||
val version_name: String?,
|
|
||||||
)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.lizongying.mytv.requests
|
|
||||||
|
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.http.GET
|
|
||||||
|
|
||||||
interface ReleaseService {
|
|
||||||
@GET("JELLY_BEAN_MR1/version.json")
|
|
||||||
fun getRelease(
|
|
||||||
): Call<ReleaseResponse>
|
|
||||||
}
|
|
||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<solid android:color="@color/white" />
|
<solid android:color="@color/white" />
|
||||||
<corners
|
<corners android:radius="4dp" /> <!-- Adjust the radius as needed -->
|
||||||
android:topLeftRadius="4dp"
|
|
||||||
android:topRightRadius="4dp" />
|
|
||||||
</shape>
|
</shape>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#FF263238" />
|
||||||
|
<corners android:radius="4dp" /> <!-- Adjust the radius as needed -->
|
||||||
|
</shape>
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/blur" />
|
|
||||||
<corners
|
|
||||||
android:bottomLeftRadius="4dp"
|
|
||||||
android:bottomRightRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/blur" />
|
|
||||||
<corners
|
|
||||||
android:topLeftRadius="4dp"
|
|
||||||
android:bottomLeftRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/blur" />
|
|
||||||
<corners
|
|
||||||
android:topRightRadius="4dp"
|
|
||||||
android:bottomRightRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/focus" />
|
|
||||||
<corners
|
|
||||||
android:bottomLeftRadius="4dp"
|
|
||||||
android:bottomRightRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/white" />
|
|
||||||
<corners
|
|
||||||
android:topLeftRadius="4dp"
|
|
||||||
android:bottomLeftRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/white" />
|
|
||||||
<corners
|
|
||||||
android:topRightRadius="4dp"
|
|
||||||
android:bottomRightRadius="4dp" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:viewportWidth="50"
|
|
||||||
android:viewportHeight="50"
|
|
||||||
android:width="62.5dp"
|
|
||||||
android:height="62.5dp">
|
|
||||||
<group
|
|
||||||
android:scaleX="0.1"
|
|
||||||
android:scaleY="-0.1"
|
|
||||||
android:translateY="50">
|
|
||||||
<path
|
|
||||||
android:pathData="M205 377c-27 -27 -40 -33 -65 -29 -30 4 -70 -19 -70 -40 0 -5 -16 -24 -35 -42 -38 -36 -44 -66 -23 -111 22 -49 51 -55 248 -55l182 0 29 29c46 46 37 106 -20 136 -20 10 -31 25 -35 49 -4 22 -20 46 -42 65 -29 26 -43 31 -85 31 -44 0 -55 -4 -84 -33zm138 2c29 -13 57 -58 57 -93 0 -17 5 -26 15 -26 24 0 65 -46 65 -71 0 -13 -10 -33 -22 -46 -21 -22 -26 -23 -205 -23 -182 0 -184 0 -208 25 -33 32 -32 70 3 105 16 15 36 40 45 54 18 27 54 35 74 15 8 -8 16 -2 29 19 9 17 27 35 38 41 28 13 80 13 109 0z"
|
|
||||||
android:fillColor="#FFEEEEEE" />
|
|
||||||
<path
|
|
||||||
android:pathData="M174 269c-10 -17 13 -36 27 -22 12 12 4 33 -11 33 -5 0 -12 -5 -16 -11z"
|
|
||||||
android:fillColor="#FFEEEEEE" />
|
|
||||||
<path
|
|
||||||
android:pathData="M294 269c-10 -17 13 -36 27 -22 12 12 4 33 -11 33 -5 0 -12 -5 -16 -11z"
|
|
||||||
android:fillColor="#FFEEEEEE" />
|
|
||||||
<path
|
|
||||||
android:pathData="M194 196c-32 -14 -50 -33 -41 -42 3 -3 20 4 38 15 43 26 75 26 118 0 34 -20 49 -20 36 1 -10 16 -69 40 -97 40 -13 -1 -37 -7 -54 -14z"
|
|
||||||
android:fillColor="#FFEEEEEE" />
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/card"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="100dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
>
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/icon"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:background="@drawable/rounded_white_top"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:padding="5dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/icon"
|
|
||||||
android:background="@drawable/rounded_dark_bottom"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="7dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:gravity="start"
|
|
||||||
android:text="Title"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:textColor="#FFEEEEEE"
|
|
||||||
android:textSize="14sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/desc"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/title"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:text="Description"
|
|
||||||
android:textColor="#B3EEEEEE"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,44 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:id="@+id/channel_fragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="90dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="60dp"
|
||||||
android:gravity="center"
|
android:layout_gravity="end|top"
|
||||||
>
|
android:layout_marginTop="20dp"
|
||||||
<FrameLayout
|
android:layout_marginEnd="170dp">
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<TextView
|
||||||
android:id="@+id/channel"
|
android:id="@+id/channel_content"
|
||||||
android:layout_width="90dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="60dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|top"
|
android:layout_gravity="end"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="0dp"
|
||||||
android:layout_marginEnd="170dp"
|
android:textColor="#FFEEEEEE"
|
||||||
android:gravity="end|bottom" >
|
android:textStyle="bold"
|
||||||
|
android:textSize="40sp" />
|
||||||
<TextView
|
</FrameLayout>
|
||||||
android:id="@+id/content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="40sp"
|
|
||||||
tools:text="99"
|
|
||||||
android:layout_alignBaseline="@+id/time"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/time"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="32sp"
|
|
||||||
tools:text="12:34" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<!-- res/layout/fragment_progress_dialog.xml -->
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="20dp">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/start_update"
|
|
||||||
tools:text="开始更新">
|
|
||||||
</Button>
|
|
||||||
<androidx.core.widget.ContentLoadingProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:indeterminate="false"
|
|
||||||
android:max="100"
|
|
||||||
android:progress="0"
|
|
||||||
android:progressDrawable="@android:drawable/progress_horizontal" />
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/error"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/black" >
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical" >
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/logo"
|
|
||||||
android:src="@drawable/sad_cloud"
|
|
||||||
android:layout_width="50dp"
|
|
||||||
android:layout_height="50dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/msg"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:textColor="#FFEEEEEE"
|
|
||||||
android:text="Message"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
</LinearLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,60 +1,53 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/info_fragment"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="320dp"
|
||||||
android:gravity="center"
|
android:layout_height="80dp"
|
||||||
>
|
android:layout_gravity="center_horizontal|bottom"
|
||||||
<FrameLayout
|
android:layout_marginBottom="20dp"
|
||||||
android:id="@+id/container"
|
android:background="@drawable/rounded_background">
|
||||||
android:layout_width="match_parent"
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/info_logo"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:padding="10dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="216dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
android:layout_marginStart="100dp"
|
||||||
|
android:background="#FF263238"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="7dp">
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:id="@+id/info"
|
android:id="@+id/textView"
|
||||||
android:layout_width="400dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="80dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal|bottom"
|
android:layout_gravity="start"
|
||||||
android:layout_marginBottom="20dp"
|
android:layout_marginTop="0dp"
|
||||||
android:orientation="horizontal">
|
android:gravity="start"
|
||||||
|
android:textColor="#FFEEEEEE"
|
||||||
|
android:textSize="22sp" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/logo"
|
android:id="@+id/info_desc"
|
||||||
android:layout_width="100dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/rounded_white_left"
|
android:layout_gravity="start"
|
||||||
android:padding="10dp" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:gravity="start"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="#B3EEEEEE"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<View
|
||||||
android:id="@+id/main"
|
android:layout_width="8dp"
|
||||||
android:layout_width="300dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_gravity="end"
|
||||||
android:layout_marginStart="0dp"
|
android:background="@drawable/rounded_background2" />
|
||||||
android:background="@drawable/rounded_dark_right"
|
</FrameLayout>
|
||||||
android:gravity="start|center_vertical"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="7dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textColor="#FFEEEEEE"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/desc"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textColor="#B3EEEEEE"
|
|
||||||
android:textSize="14sp" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/loading"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/black"
|
|
||||||
>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center" >
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/bar"
|
|
||||||
android:layout_width="50dp"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:indeterminateTint="@color/white"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="false"
|
|
||||||
android:gravity="center"
|
|
||||||
>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/menu"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/scroll"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
>
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,11 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/player"
|
android:id="@+id/player_fragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:keepScreenOn="true">
|
android:keepScreenOn="true">
|
||||||
|
|
||||||
|
<SurfaceView
|
||||||
|
android:id="@+id/surface_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:resize_mode="fill"
|
||||||
|
app:use_controller="false" />
|
||||||
|
|
||||||
<androidx.media3.ui.PlayerView
|
<androidx.media3.ui.PlayerView
|
||||||
android:id="@+id/player_view"
|
android:id="@+id/player_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/row"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="false"
|
|
||||||
>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/header"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:layout_marginStart="20dp"
|
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textColor="#FFEEEEEE"
|
|
||||||
android:textSize="22sp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/items"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,28 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/setting"
|
android:id="@+id/dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
>
|
>
|
||||||
<ScrollView
|
<LinearLayout
|
||||||
android:id="@+id/container"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content">
|
||||||
android:fillViewport="true"
|
|
||||||
>
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/content"
|
|
||||||
android:layout_width="300dp"
|
android:layout_width="300dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingTop="20dp"
|
android:paddingTop="20dp"
|
||||||
android:paddingBottom="20dp"
|
android:paddingLeft="7dp"
|
||||||
android:paddingLeft="10dp"
|
android:paddingRight="7dp"
|
||||||
android:paddingRight="10dp"
|
android:background="#FF263238"
|
||||||
android:background="@drawable/rounded_dark_left"
|
|
||||||
>
|
>
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/name"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
@@ -33,10 +27,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:text="当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
android:text="当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
||||||
android:textSize="14sp"
|
|
||||||
/>
|
/>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="300dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
>
|
>
|
||||||
@@ -44,7 +37,7 @@
|
|||||||
android:id="@+id/check_version"
|
android:id="@+id/check_version"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="14sp"
|
android:layout_marginEnd="10dp"
|
||||||
android:text="@string/check_version"
|
android:text="@string/check_version"
|
||||||
/>
|
/>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
@@ -55,74 +48,45 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/version_name"
|
android:id="@+id/version_name"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- <androidx.core.widget.ContentLoadingProgressBar-->
|
|
||||||
<!-- android:id="@+id/progressBar"-->
|
|
||||||
<!-- android:layout_width="match_parent"-->
|
|
||||||
<!-- android:layout_height="wrap_content"-->
|
|
||||||
<!-- android:indeterminate="false"-->
|
|
||||||
<!-- android:max="100"-->
|
|
||||||
<!-- android:progress="0"-->
|
|
||||||
<!-- android:visibility="gone"-->
|
|
||||||
<!-- android:progressDrawable="@android:drawable/progress_horizontal" />-->
|
|
||||||
<Button
|
|
||||||
android:id="@+id/clear"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:text="@string/clear"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/exit"
|
android:id="@+id/exit"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="14sp"
|
android:layout_marginEnd="10dp"
|
||||||
android:text="@string/exit"
|
android:text="@string/exit"
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/switch_channel_reversal"
|
android:id="@+id/switch_channel_reversal"
|
||||||
android:text="@string/title_channel_reversal"
|
android:text="@string/title_channel_reversal"
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/switch_channel_num"
|
android:id="@+id/switch_channel_num"
|
||||||
android:text="@string/title_channel_num"
|
android:text="@string/title_channel_num"
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/switch_time"
|
android:id="@+id/switch_time"
|
||||||
android:text="@string/title_time"
|
android:text="@string/title_time"
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/switch_boot_startup"
|
android:id="@+id/switch_boot_startup"
|
||||||
android:text="@string/title_boot_startup"
|
android:text="@string/title_boot_startup"
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<Switch
|
|
||||||
android:id="@+id/switch_grid"
|
|
||||||
android:text="@string/title_grid"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
<ImageView
|
||||||
<ImageView
|
android:layout_width="300dp"
|
||||||
android:id="@+id/appreciate"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="300dp"
|
android:src="@drawable/appreciate"
|
||||||
android:layout_height="wrap_content"
|
android:background="@color/white" />
|
||||||
android:src="@drawable/appreciate"
|
</LinearLayout>
|
||||||
android:background="@drawable/rounded_white_right" />
|
</FrameLayout>
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,45 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:id="@+id/time"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="100dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="40dp"
|
||||||
android:gravity="center"
|
android:layout_gravity="end|top"
|
||||||
>
|
android:layout_marginTop="25dp"
|
||||||
<FrameLayout
|
android:layout_marginEnd="50dp">
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<TextView
|
||||||
android:id="@+id/time"
|
android:id="@+id/content"
|
||||||
android:layout_width="120dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="60dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|top"
|
android:layout_gravity="end"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="0dp"
|
||||||
android:layout_marginEnd="50dp"
|
android:textColor="#FFEEEEEE"
|
||||||
android:gravity="end|bottom" >
|
android:textStyle="bold"
|
||||||
|
android:textSize="32sp" />
|
||||||
<TextView
|
</FrameLayout>
|
||||||
android:id="@+id/channel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="40sp"
|
|
||||||
tools:text="99"
|
|
||||||
android:layout_alignBaseline="@+id/content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="32sp"
|
|
||||||
tools:text="12:34" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
<color name="focus">#0096a6</color>
|
||||||
|
<color name="fastlane_background">#30000000</color>
|
||||||
<color name="black">#000</color>
|
<color name="black">#000</color>
|
||||||
<color name="white">#FFF</color>
|
<color name="white">#FFF</color>
|
||||||
<color name="focus">#0096a6</color>
|
|
||||||
<color name="blur">#223239</color>
|
|
||||||
<color name="ic_launcher_background">#223239</color>
|
<color name="ic_launcher_background">#223239</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="server_url">http://localhost:8080</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -4,9 +4,7 @@
|
|||||||
<string name="title_channel_num">换台时显示频道号</string>
|
<string name="title_channel_num">换台时显示频道号</string>
|
||||||
<string name="check_version">检查更新</string>
|
<string name="check_version">检查更新</string>
|
||||||
<string name="title_boot_startup">开机自启</string>
|
<string name="title_boot_startup">开机自启</string>
|
||||||
<string name="title_grid">频道列表采用网格样式</string>
|
<string name="dismiss_error">好的</string>
|
||||||
<string name="title_time">显示时间</string>
|
<string name="title_time">显示时间</string>
|
||||||
<string name="clear">恢复默认</string>
|
<string name="exit">退出</string>
|
||||||
<string name="exit">退出应用</string>
|
|
||||||
<string name="start_update">开始更新</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
|
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
|
||||||
|
<item name="lbImageCardViewType">Title|Content</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="CustomImageCardTheme" parent="Theme.Leanback">
|
||||||
|
<item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.MyTV" parent="@style/Theme.Leanback">
|
<style name="Theme.MyTV" parent="@style/Theme.Leanback">
|
||||||
<item name="android:fitsSystemWindows">false</item>
|
<item name="browsePaddingStart">11dp</item>
|
||||||
|
<item name="browsePaddingEnd">11dp</item>
|
||||||
|
<item name="browseRowsMarginTop">54dp</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<external-path name="external_files" path="." />
|
|
||||||
</paths>
|
|
||||||
Executable → Regular
+1
-1
@@ -1 +1 @@
|
|||||||
{"version_code": 33620480, "version_name": "v2.1.2"}
|
{"version_code": 33619968, "version_name": "v2.1.0"}
|
||||||
|
|||||||
Reference in New Issue
Block a user