Compare commits

..
2 Commits
Author SHA1 Message Date
Li ZongYing 3eb6757543 change channel info style 2023-12-28 20:30:12 +08:00
Li ZongYing 72e893b73a show info 2023-12-27 23:53:03 +08:00
13 changed files with 182 additions and 80 deletions
+5
View File
@@ -13,6 +13,11 @@
## 更新日志 ## 更新日志
### v1.2.5
* 美化频道信息显示
* 优化节目单获取
### v1.2.4 ### v1.2.4
* 改变换台滑动方向,上一个频道下滑,下一个频道上滑 * 改变换台滑动方向,上一个频道下滑,下一个频道上滑
@@ -1,16 +1,23 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.os.Bundle import android.os.Bundle
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.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.lizongying.mytv.databinding.InfoBinding import com.lizongying.mytv.databinding.InfoBinding
import com.lizongying.mytv.models.TVViewModel
class InfoFragment : Fragment() { class InfoFragment : Fragment() {
private var _binding: InfoBinding? = null private var _binding: InfoBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val handler = Handler()
private val delay: Long = 3000
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@@ -19,8 +26,39 @@ class InfoFragment : Fragment() {
return binding.root return binding.root
} }
fun setInfo(info: TV) { override fun onResume() {
binding.textView.text = info.title super.onResume()
// Use a Handler to delay the fragment transaction
handler.postDelayed(removeRunnable, delay)
}
fun show(tvViewModel: TVViewModel) {
Log.i("", "show")
binding.textView.text = tvViewModel.title.value
Glide.with(this)
.load(tvViewModel.logo.value)
.into(binding.infoLogo)
val program = tvViewModel.getProgramOne()
if (program != null) {
binding.infoDesc.text = program.name
}
handler.removeCallbacks(removeRunnable)
view?.visibility = View.VISIBLE
handler.postDelayed(removeRunnable, delay)
}
override fun onPause() {
super.onPause()
Log.i("", "onPause")
// Cancel the delayed task when the fragment is paused
handler.removeCallbacks(removeRunnable)
}
private val removeRunnable = Runnable {
Log.i("", "hide")
view?.visibility = View.GONE
} }
override fun onDestroyView() { override fun onDestroyView() {
@@ -46,8 +46,8 @@ class MainActivity : FragmentActivity() {
if (savedInstanceState == null) { if (savedInstanceState == null) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, playerFragment)
.add(R.id.main_browse_fragment, mainFragment)
.add(R.id.main_browse_fragment, infoFragment) .add(R.id.main_browse_fragment, infoFragment)
.add(R.id.main_browse_fragment, mainFragment)
.hide(infoFragment) .hide(infoFragment)
.commit() .commit()
mainFragment.view?.requestFocus() mainFragment.view?.requestFocus()
@@ -55,25 +55,8 @@ class MainActivity : FragmentActivity() {
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
} }
fun switchInfoFragment(tv: TV) { fun showInfoFragment(tvViewModel: TVViewModel) {
infoFragment.setInfo(tv) infoFragment.show(tvViewModel)
if (infoFragment.isHidden) {
supportFragmentManager.beginTransaction().show(infoFragment).commit()
}
}
fun showInfoFragment(tv: TV) {
infoFragment.setInfo(tv)
supportFragmentManager.beginTransaction()
.show(infoFragment)
.commit()
}
fun hideInfoFragment() {
supportFragmentManager.beginTransaction()
.hide(infoFragment)
.commit()
} }
fun play(tvViewModel: TVViewModel) { fun play(tvViewModel: TVViewModel) {
@@ -3,8 +3,9 @@ package com.lizongying.mytv
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.leanback.app.BrowseSupportFragment import androidx.leanback.app.BrowseSupportFragment
import androidx.leanback.widget.ArrayObjectAdapter import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.HeaderItem import androidx.leanback.widget.HeaderItem
@@ -17,6 +18,7 @@ import androidx.leanback.widget.Presenter
import androidx.leanback.widget.Row import androidx.leanback.widget.Row
import androidx.leanback.widget.RowPresenter import androidx.leanback.widget.RowPresenter
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.lizongying.mytv.Utils.getDateTimestamp
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 kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -36,6 +38,9 @@ class MainFragment : BrowseSupportFragment() {
private var lastVideoUrl: String = "" private var lastVideoUrl: String = ""
private val handler = Handler(Looper.getMainLooper())
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
headersState = HEADERS_DISABLED headersState = HEADERS_DISABLED
@@ -48,6 +53,9 @@ class MainFragment : BrowseSupportFragment() {
request = activity?.let { Request(it) } request = activity?.let { Request(it) }
loadRows() loadRows()
mUpdateProgramRunnable = UpdateProgramRunnable()
handler.post(mUpdateProgramRunnable)
setupEventListeners() setupEventListeners()
view?.post { view?.post {
@@ -64,7 +72,6 @@ class MainFragment : BrowseSupportFragment() {
) { ) {
Log.i(TAG, "ready ${tvViewModel.title.value}") Log.i(TAG, "ready ${tvViewModel.title.value}")
(activity as? MainActivity)?.play(tvViewModel) (activity as? MainActivity)?.play(tvViewModel)
// (activity as? MainActivity)?.switchInfoFragment(item)
} }
} }
tvViewModel.change.observe(viewLifecycleOwner) { _ -> tvViewModel.change.observe(viewLifecycleOwner) { _ ->
@@ -76,42 +83,57 @@ class MainFragment : BrowseSupportFragment() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
tvViewModel.let { request?.fetchData(it) } tvViewModel.let { request?.fetchData(it) }
} }
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
setSelectedPosition( setSelectedPosition(
tvViewModel.getRowPosition(), true, tvViewModel.getRowPosition(), true,
SelectItemViewHolderTask(tvViewModel.getItemPosition()) SelectItemViewHolderTask(tvViewModel.getItemPosition())
) )
Toast.makeText(
activity,
title,
Toast.LENGTH_SHORT
).show()
} else { } else {
if (check(tvViewModel)) { if (check(tvViewModel)) {
(activity as? MainActivity)?.play(tvViewModel) (activity as? MainActivity)?.play(tvViewModel)
// (activity as? MainActivity)?.switchInfoFragment(item) (activity as? MainActivity)?.showInfoFragment(tvViewModel)
setSelectedPosition( setSelectedPosition(
tvViewModel.getRowPosition(), true, tvViewModel.getRowPosition(), true,
SelectItemViewHolderTask(tvViewModel.getItemPosition()) SelectItemViewHolderTask(tvViewModel.getItemPosition())
) )
Toast.makeText(
activity,
title,
Toast.LENGTH_SHORT
).show()
} }
} }
} }
} }
tvViewModel.program.observe(viewLifecycleOwner) { _ -> }
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacks(mUpdateProgramRunnable)
}
fun updateProgram(tvViewModel: TVViewModel) {
val timestamp = getDateTimestamp()
if (timestamp - tvViewModel.programUpdateTime > 60) {
if (tvViewModel.program.value!!.isEmpty()) { if (tvViewModel.program.value!!.isEmpty()) {
if (tvViewModel.programId.value != null) { tvViewModel.programUpdateTime = timestamp
Log.i(TAG, "get program ${tvViewModel.title.value}") request?.fetchProgram(tvViewModel)
} else {
if (timestamp - tvViewModel.program.value!!.last().et < 600) {
tvViewModel.programUpdateTime = timestamp
request?.fetchProgram(tvViewModel) request?.fetchProgram(tvViewModel)
} }
} }
} }
} }
inner class UpdateProgramRunnable : Runnable {
override fun run() {
tvListViewModel.getTVListViewModel().value?.filter { it.programId.value != null }
?.forEach { tvViewModel ->
updateProgram(
tvViewModel
)
}
handler.postDelayed(this, 60000)
}
} }
fun check(tvViewModel: TVViewModel): Boolean { fun check(tvViewModel: TVViewModel): Boolean {
@@ -5,6 +5,7 @@ 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.getDateFormat
import com.lizongying.mytv.api.ApiClient import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.api.BtraceClient import com.lizongying.mytv.api.BtraceClient
import com.lizongying.mytv.api.LiveInfo import com.lizongying.mytv.api.LiveInfo
@@ -20,9 +21,6 @@ import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgram
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
@@ -34,6 +32,7 @@ class Request(var context: Context) {
private var yspBtraceService: YSPBtraceService? = null private var yspBtraceService: YSPBtraceService? = null
private var yspProtoService: YSPProtoService? = null private var yspProtoService: YSPProtoService? = null
// TODO onDestroy
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private lateinit var myRunnable: MyRunnable private lateinit var myRunnable: MyRunnable
@@ -175,13 +174,13 @@ class Request(var context: Context) {
livepid = pid, livepid = pid,
sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid", sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid",
playno = ysp?.getRand()!!, playno = ysp?.getRand()!!,
ftime = getCurrentDate2(), ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"),
seq = tvModel.seq.toString(), seq = tvModel.seq.toString(),
) )
?.enqueue(object : Callback<Void> { ?.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")
tvModel.firstSource() tvModel.firstSource()
@@ -238,20 +237,9 @@ class Request(var context: Context) {
}) })
} }
private fun getCurrentDate(): String { fun fetchProgram(tvViewModel: TVViewModel) {
val currentDate = Date() val title = tvViewModel.title.value
val formatter = SimpleDateFormat("yyyyMMdd", Locale.CHINA) yspProtoService?.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd"))
return formatter.format(currentDate)
}
private fun getCurrentDate2(): String {
val currentDate = Date()
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
return formatter.format(currentDate)
}
fun fetchProgram(tvModel: TVViewModel) {
yspProtoService?.getProgram(tvModel.programId.value!!, getCurrentDate())
?.enqueue(object : Callback<epgProgramModel.Response> { ?.enqueue(object : Callback<epgProgramModel.Response> {
override fun onResponse( override fun onResponse(
call: Call<epgProgramModel.Response>, call: Call<epgProgramModel.Response>,
@@ -260,13 +248,14 @@ class Request(var context: Context) {
if (response.isSuccessful) { if (response.isSuccessful) {
val program = response.body() val program = response.body()
if (program != null) { if (program != null) {
tvModel.addProgram(program.dataListList) tvViewModel.addProgram(program.dataListList)
Log.i(TAG, "$title program ${program.dataListList.size}")
} }
} }
} }
override fun onFailure(call: Call<epgProgramModel.Response>, t: Throwable) { override fun onFailure(call: Call<epgProgramModel.Response>, t: Throwable) {
Log.e(TAG, "Program request failed", t) Log.e(TAG, "$title program request failed $t")
} }
}) })
} }
@@ -69,10 +69,10 @@ CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8,https://resource
四川卫视,http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp,600002516,2000295003 四川卫视,http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp,600002516,2000295003
东南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226341/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp,600002484,2000292503 东南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226341/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp,600002484,2000292503
海南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226465/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp,600002506,2000291503 海南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226465/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp,600002506,2000291503
三沙卫视,https://pullsstv90080111.ssws.tv/live/SSTV20220729.m3u8
移动专区 移动专区
三沙卫视,https://pullsstv90080111.ssws.tv/live/SSTV20220729.m3u8
天津卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221225740/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226204/index.m3u8 天津卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221225740/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226204/index.m3u8
吉林卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226397/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225792/index.m3u8 吉林卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226397/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225792/index.m3u8
@@ -0,0 +1,15 @@
package com.lizongying.mytv
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object Utils {
fun getDateFormat(format: String): String {
return SimpleDateFormat(format, Locale.CHINA).format(Date())
}
fun getDateTimestamp(): Int {
return (Date().time / 1000).toInt()
}
}
@@ -11,6 +11,7 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.hls.HlsMediaSource
import com.lizongying.mytv.TV import com.lizongying.mytv.TV
import com.lizongying.mytv.Utils.getDateTimestamp
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 java.util.Date import java.util.Date
@@ -231,6 +232,8 @@ class TVViewModel(private var tv: TV) : ViewModel() {
private var rowPosition: Int = 0 private var rowPosition: Int = 0
private var itemPosition: Int = 0 private var itemPosition: Int = 0
var programUpdateTime: Int = 0
private val _programId = MutableLiveData<String>() private val _programId = MutableLiveData<String>()
val programId: LiveData<String> val programId: LiveData<String>
get() = _programId get() = _programId
@@ -324,7 +327,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_title.value = tv.title _title.value = tv.title
_videoUrl.value = tv.videoUrl _videoUrl.value = tv.videoUrl
_videoIndex.value = tv.videoIndex _videoIndex.value = tv.videoIndex
Log.i(TAG, "tv.title ${tv.title} ${mappingLogo[tv.title]}") Log.d(TAG, "${tv.title} ${mappingLogo[tv.title]}")
if (mappingLogo[tv.title] != null) { if (mappingLogo[tv.title] != null) {
_logo.value = mappingLogo[tv.title] _logo.value = mappingLogo[tv.title]
} }
@@ -376,10 +379,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
return mapping[tv.title] return mapping[tv.title]
} }
fun getProgram(): MutableList<Program>? { // fun getProgram(): MutableList<Program>? {
_program.value = (_program.value?.filter { it.et > (Date().time / 1000) })?.toMutableList() // _program.value = (_program.value?.filter { it.et > (Date().time / 1000) })?.toMutableList()
return _program.value?.subList(0, 2) // return _program.value?.subList(0, 2)
} // }
fun getProgramOne(): Program? { fun getProgramOne(): Program? {
val programNew = (_program.value?.filter { it.et > (Date().time / 1000) })?.toMutableList() val programNew = (_program.value?.filter { it.et > (Date().time / 1000) })?.toMutableList()
@@ -393,7 +396,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
} }
fun addProgram(p: MutableList<Program>) { fun addProgram(p: MutableList<Program>) {
val p1 = (p.filter { it.et > (Date().time / 1000) }).toMutableList() val timestamp = getDateTimestamp()
// after now & not empty & different
val p1 = (p.filter { it.et > timestamp }).toMutableList()
if (p1.isEmpty() || _program.value == p1) { if (p1.isEmpty() || _program.value == p1) {
return return
} }
@@ -402,7 +408,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_program.value = p1 _program.value = p1
} else { } else {
_program.value = _program.value =
((_program.value?.filter { it.et > (Date().time / 1000) && it.st < p1.first().st })?.plus( ((_program.value?.filter { it.et > timestamp && it.st < p1.first().st })?.plus(
p1 p1
))?.toMutableList() ))?.toMutableList()
} }
@@ -415,7 +421,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
mHeaders = headers mHeaders = headers
} }
fun setMinimumLoadableRetryCount(minimumLoadableRetryCount: Int) { fun setMinimumLoadableRetryCount(minimumLoadableRetryCount: Int) {
mMinimumLoadableRetryCount = minimumLoadableRetryCount mMinimumLoadableRetryCount = minimumLoadableRetryCount
} }
@@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="4dp" /> <!-- Adjust the radius as needed -->
</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>
+40 -5
View File
@@ -5,15 +5,50 @@
android:layout_height="80dp" android:layout_height="80dp"
android:layout_gravity="center_horizontal|bottom" android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="20dp" android:layout_marginBottom="20dp"
android:background="@color/fastlane_background" android:background="@drawable/rounded_background">
>
<ImageView
android:id="@+id/info_logo"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:contentDescription="@string/logo"
android:padding="10dp" />
<LinearLayout
android:layout_width="216dp"
android:layout_height="match_parent"
android:layout_marginStart="100dp"
android:background="#FF263238"
android:gravity="start|center_vertical"
android:orientation="vertical"
android:padding="7dp">
<TextView <TextView
android:id="@+id/textView" android:id="@+id/textView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top" android:layout_gravity="start"
android:layout_marginTop="0dp"
android:gravity="start"
android:textColor="#FFEEEEEE"
android:textSize="20sp" />
<TextView
android:id="@+id/info_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:textSize="40sp" android:gravity="start"
/> android:singleLine="true"
android:textColor="#B3EEEEEE"
android:textSize="16sp" />
</LinearLayout>
<View
android:layout_width="8dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="@drawable/rounded_background2" />
</FrameLayout> </FrameLayout>
+1
View File
@@ -1,4 +1,5 @@
<resources> <resources>
<color name="fastlane_background">#30000000</color> <color name="fastlane_background">#30000000</color>
<color name="black">#000</color> <color name="black">#000</color>
<color name="white">#FFF</color>
</resources> </resources>
+1
View File
@@ -1,3 +1,4 @@
<resources> <resources>
<string name="app_name">我的电视</string> <string name="app_name">我的电视</string>
<string name="logo">logo</string>
</resources> </resources>