mirror of
https://github.com/mediathekview/zapp.git
synced 2024-09-20 20:23:04 +02:00
Add tab navigation
This commit is contained in:
parent
51acdbc16c
commit
c1a2941f54
@ -169,4 +169,5 @@ dependencies {
|
|||||||
|
|
||||||
// android tv
|
// android tv
|
||||||
implementation 'androidx.leanback:leanback:1.0.0'
|
implementation 'androidx.leanback:leanback:1.0.0'
|
||||||
|
implementation "androidx.leanback:leanback-tab:1.1.0-beta01"
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package de.christinecoenen.code.zapp.tv.channels
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import de.christinecoenen.code.zapp.app.livestream.ui.list.adapter.ChannelListAdapter
|
||||||
|
import de.christinecoenen.code.zapp.app.livestream.ui.list.adapter.ListItemListener
|
||||||
|
import de.christinecoenen.code.zapp.databinding.TvFragmentChannelListBinding
|
||||||
|
import de.christinecoenen.code.zapp.models.channels.ChannelModel
|
||||||
|
import de.christinecoenen.code.zapp.models.channels.ISortableChannelList
|
||||||
|
import de.christinecoenen.code.zapp.models.channels.json.SortableVisibleJsonChannelList
|
||||||
|
import de.christinecoenen.code.zapp.tv.player.PlayerActivity
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelListFragment : Fragment(), ListItemListener {
|
||||||
|
|
||||||
|
private lateinit var channelList: ISortableChannelList
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
val binding = TvFragmentChannelListBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
channelList = SortableVisibleJsonChannelList(requireContext())
|
||||||
|
|
||||||
|
binding.grid.setNumColumns(2)
|
||||||
|
binding.grid.adapter = ChannelListAdapter(channelList, this, this)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClick(channel: ChannelModel) {
|
||||||
|
val intent = PlayerActivity.getStartIntent(requireContext(), channel)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemLongClick(channel: ChannelModel, view: View) {
|
||||||
|
// no action
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ class ErrorFragment : ErrorSupportFragment() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
message = activity?.intent?.getStringExtra(ErrorActivity.EXTRA_MESSAGE)
|
message = activity?.intent?.getStringExtra(ErrorActivity.EXTRA_MESSAGE)
|
||||||
?: throw IllegalArgumentException("message extra has to be set")
|
//?: throw IllegalArgumentException("message extra has to be set")
|
||||||
|
|
||||||
title = getString(R.string.error_informal)
|
title = getString(R.string.error_informal)
|
||||||
imageDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.ic_sad_tv)
|
imageDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.ic_sad_tv)
|
||||||
|
@ -5,40 +5,34 @@ 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 de.christinecoenen.code.zapp.app.livestream.ui.list.adapter.ChannelListAdapter
|
|
||||||
import de.christinecoenen.code.zapp.app.livestream.ui.list.adapter.ListItemListener
|
|
||||||
import de.christinecoenen.code.zapp.databinding.TvFragmentMainBinding
|
import de.christinecoenen.code.zapp.databinding.TvFragmentMainBinding
|
||||||
import de.christinecoenen.code.zapp.models.channels.ChannelModel
|
|
||||||
import de.christinecoenen.code.zapp.models.channels.ISortableChannelList
|
|
||||||
import de.christinecoenen.code.zapp.models.channels.json.SortableVisibleJsonChannelList
|
|
||||||
import de.christinecoenen.code.zapp.tv.player.PlayerActivity
|
|
||||||
|
|
||||||
|
|
||||||
class MainFragment : Fragment(), ListItemListener {
|
class MainFragment : Fragment() {
|
||||||
|
|
||||||
private lateinit var channelList: ISortableChannelList
|
private var _binding: TvFragmentMainBinding? = null
|
||||||
|
private val binding: TvFragmentMainBinding get() = _binding!!
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val binding = TvFragmentMainBinding.inflate(inflater, container, false)
|
_binding = TvFragmentMainBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
channelList = SortableVisibleJsonChannelList(requireContext())
|
binding.viewpager.adapter = MainNavPagerAdapter(requireContext(), requireFragmentManager())
|
||||||
|
binding.tabs.setupWithViewPager(binding.viewpager)
|
||||||
binding.grid.setNumColumns(2)
|
|
||||||
binding.grid.adapter = ChannelListAdapter(channelList, this, this)
|
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(channel: ChannelModel) {
|
override fun onDestroyView() {
|
||||||
val intent = PlayerActivity.getStartIntent(requireContext(), channel)
|
super.onDestroyView()
|
||||||
startActivity(intent)
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemLongClick(channel: ChannelModel, view: View) {
|
override fun onResume() {
|
||||||
// no action
|
super.onResume()
|
||||||
|
binding.viewpager.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package de.christinecoenen.code.zapp.tv.main
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
import de.christinecoenen.code.zapp.R
|
||||||
|
import de.christinecoenen.code.zapp.tv.channels.ChannelListFragment
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class MainNavPagerAdapter(
|
||||||
|
private val context: Context,
|
||||||
|
fragmentManger: FragmentManager
|
||||||
|
) : FragmentPagerAdapter(fragmentManger) {
|
||||||
|
|
||||||
|
private val navItems = listOf(
|
||||||
|
MainNavItem(R.string.activity_main_tab_live, ChannelListFragment::class),
|
||||||
|
MainNavItem(R.string.menu_about_short, ChannelListFragment::class),
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getCount(): Int = navItems.size
|
||||||
|
|
||||||
|
override fun getItem(position: Int): Fragment {
|
||||||
|
return navItems[position].createFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
|
return navItems[position].getTitle(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class MainNavItem<T : Fragment>(
|
||||||
|
@StringRes val titleResId: Int,
|
||||||
|
val fragmentClass: KClass<T>
|
||||||
|
) {
|
||||||
|
fun createFragment(): T = fragmentClass.java.newInstance()
|
||||||
|
fun getTitle(context: Context) = context.getString(titleResId)
|
||||||
|
}
|
||||||
|
}
|
23
app/src/main/res/layout/tv_fragment_channel_list.xml
Normal file
23
app/src/main/res/layout/tv_fragment_channel_list.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?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"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingHorizontal="64dp">
|
||||||
|
|
||||||
|
<androidx.leanback.widget.VerticalGridView
|
||||||
|
android:id="@+id/grid"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:horizontalSpacing="16dp"
|
||||||
|
android:paddingTop="64dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:verticalSpacing="8dp"
|
||||||
|
app:focusOutFront="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:listitem="@layout/fragment_channel_list_item" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,23 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingHorizontal="64dp">
|
|
||||||
|
|
||||||
<androidx.leanback.widget.VerticalGridView
|
<androidx.leanback.tab.LeanbackTabLayout
|
||||||
android:id="@+id/grid"
|
android:id="@+id/tabs"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:theme="@style/Theme.AppCompat"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tabIndicatorColor="@android:color/white"
|
||||||
|
app:tabTextAppearance="@style/TextAppearance.Leanback.ImageCardView.Title" />
|
||||||
|
|
||||||
|
<androidx.leanback.tab.LeanbackViewPager
|
||||||
|
android:id="@+id/viewpager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:clipToPadding="false"
|
|
||||||
android:horizontalSpacing="16dp"
|
|
||||||
android:paddingTop="64dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
android:verticalSpacing="8dp"
|
|
||||||
app:focusOutFront="true"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/tabs">
|
||||||
tools:listitem="@layout/fragment_channel_list_item" />
|
|
||||||
|
</androidx.leanback.tab.LeanbackViewPager>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
<string name="menu_refresh">Refresh</string>
|
<string name="menu_refresh">Refresh</string>
|
||||||
<string name="menu_retry">Reload</string>
|
<string name="menu_retry">Reload</string>
|
||||||
<string name="menu_about">About Zapp</string>
|
<string name="menu_about">About Zapp</string>
|
||||||
|
<string name="menu_about_short">About</string>
|
||||||
<string name="menu_settings">Settings</string>
|
<string name="menu_settings">Settings</string>
|
||||||
<string name="menu_feedback">Feedback</string>
|
<string name="menu_feedback">Feedback</string>
|
||||||
<string name="menu_filter">Filter</string>
|
<string name="menu_filter">Filter</string>
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
<string name="menu_refresh">Aktualisieren</string>
|
<string name="menu_refresh">Aktualisieren</string>
|
||||||
<string name="menu_retry">Wiederholen</string>
|
<string name="menu_retry">Wiederholen</string>
|
||||||
<string name="menu_about">Über Zapp</string>
|
<string name="menu_about">Über Zapp</string>
|
||||||
|
<string name="menu_about_short">Über</string>
|
||||||
<string name="menu_settings">Einstellungen</string>
|
<string name="menu_settings">Einstellungen</string>
|
||||||
<string name="menu_feedback">Feedback</string>
|
<string name="menu_feedback">Feedback</string>
|
||||||
<string name="menu_filter">Filter</string>
|
<string name="menu_filter">Filter</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user