├── .gitignore ├── .idea ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── runConfigurations.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── androijo │ │ └── sample │ │ ├── activities │ │ └── SampleActivity.kt │ │ ├── fragments │ │ ├── AbstractCardPresenter.kt │ │ ├── CardListRow.kt │ │ ├── CardPresenter.kt │ │ ├── CardPresenterSelector.kt │ │ ├── MoviesFragment.kt │ │ ├── MusicFragment.kt │ │ ├── NewsFragment.kt │ │ ├── PodcastsFragment.kt │ │ ├── RowPresenterSelector.kt │ │ ├── SettingsFragment.kt │ │ └── ShowsFragment.kt │ │ └── interfaces │ │ └── NavigationMenuCallback.kt │ └── res │ ├── anim │ └── slide_in_left.xml │ ├── drawable │ ├── app_icon_your_company.png │ ├── ic_nav_bg_closed.xml │ └── ic_nav_bg_open.xml │ ├── layout │ ├── activity_sample.xml │ └── card_subject.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── nav_closed.png ├── nav_open.png ├── nav_open_2.png ├── settings.gradle └── tvnavigation ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── androijo │ └── tvnavigation │ └── ExampleInstrumentedTest.kt ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── androijo │ │ └── tvnavigation │ │ ├── NavigationMenu.kt │ │ ├── interfaces │ │ ├── FragmentChangeListener.kt │ │ └── NavigationStateListener.kt │ │ └── utils │ │ └── Constants.kt └── res │ ├── anim │ └── slide_in_left_menu_name.xml │ ├── drawable │ ├── ic_movie_selected.xml │ ├── ic_movie_unselected.xml │ ├── ic_music_selected.xml │ ├── ic_music_unselected.xml │ ├── ic_news_selected.xml │ ├── ic_news_unselected.xml │ ├── ic_podcast_selected.xml │ ├── ic_podcast_unselected.xml │ ├── ic_settings_selected.xml │ ├── ic_settings_unselected.xml │ ├── ic_shows_selected.xml │ └── ic_shows_unselected.xml │ ├── layout │ └── fragment_nav_menu.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ └── strings.xml └── test └── java └── com └── androijo └── tvnavigation └── ExampleUnitTest.kt /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | TV Menu Navigation -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Arpit Johri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TVNavigation 2 | An Android TV navigation library inspired by Netflix. 3 | 4 | As we all are aware of the limitations of Leanback Library. This is an effort in that direction to ease it. 5 | 6 | A custom navigation implementation supported with RowsSupportFragment for Android TV. 7 | 8 | I will be making this 100% dynamic[A Re-Usable Library] in coming weeks. But sharing it now with my fellow developers. 9 | Because I feel the Pain of Android TV Development :D 10 | Also this is open for contribution so feel free to fork and send me a PR Cheers!! 11 | 12 | 13 | [![](https://jitpack.io/v/Arpit0492/TVNavigationMenu.svg)](https://jitpack.io/#Arpit0492/TVNavigationMenu) 14 | ![Navigation Open](nav_open.png) 15 | ![Navigation Open](nav_open_2.png) 16 | ![Navigation Closed](nav_closed.png) 17 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion "29.0.3" 8 | 9 | defaultConfig { 10 | applicationId "com.androijo.navigation" 11 | minSdkVersion 21 12 | targetSdkVersion 29 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: "libs", include: ["*.jar"]) 28 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 29 | implementation 'androidx.core:core-ktx:1.3.0' 30 | implementation 'androidx.leanback:leanback:1.0.0' 31 | 32 | implementation 'androidx.appcompat:appcompat:1.1.0' 33 | implementation 'com.github.bumptech.glide:glide:3.8.0' 34 | // implementation 'com.github.Arpit0492:TVNavigationMenu:0.1.0' 35 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 36 | implementation project(path: ':tvnavigation') 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/activities/SampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.activities 2 | 3 | import android.os.Bundle 4 | import android.view.animation.AnimationUtils 5 | import androidx.fragment.app.Fragment 6 | import androidx.fragment.app.FragmentActivity 7 | import com.androijo.sample.R 8 | import com.androijo.sample.fragments.* 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | import com.androijo.tvnavigation.NavigationMenu 11 | import com.androijo.tvnavigation.interfaces.FragmentChangeListener 12 | import com.androijo.tvnavigation.interfaces.NavigationStateListener 13 | import com.androijo.tvnavigation.utils.Constants 14 | import kotlinx.android.synthetic.main.activity_sample.* 15 | 16 | class SampleActivity : FragmentActivity(), NavigationStateListener, FragmentChangeListener, 17 | NavigationMenuCallback { 18 | 19 | private lateinit var moviesFragment: MoviesFragment 20 | private lateinit var showsFragment: ShowsFragment 21 | private lateinit var musicFragment: MusicFragment 22 | private lateinit var podcastsFragment: PodcastsFragment 23 | private lateinit var newsFragment: NewsFragment 24 | private lateinit var settingsFragment: SettingsFragment 25 | private lateinit var navMenuFragment: NavigationMenu 26 | private var currentSelectedFragment = Constants.nav_menu_movies 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | setContentView(R.layout.activity_sample) 31 | navMenuFragment = NavigationMenu() 32 | fragmentReplacer(nav_fragment.id, navMenuFragment) 33 | moviesFragment = MoviesFragment() 34 | fragmentReplacer(main_FL.id, moviesFragment) 35 | } 36 | 37 | private fun fragmentReplacer(containerId: Int, fragment: Fragment) { 38 | supportFragmentManager.beginTransaction().replace(containerId, fragment).commit() 39 | } 40 | 41 | /** 42 | * communication from left-side navigation to right-side content 43 | */ 44 | override fun onStateChanged(expanded: Boolean, lastSelected: String?) { 45 | if (!expanded) { 46 | nav_fragment.setBackgroundResource(R.drawable.ic_nav_bg_closed) 47 | nav_fragment.clearFocus() 48 | 49 | when (currentSelectedFragment) { 50 | Constants.nav_menu_movies -> { 51 | currentSelectedFragment = Constants.nav_menu_movies 52 | moviesFragment.restoreSelection() 53 | } 54 | Constants.nav_menu_music -> { 55 | currentSelectedFragment = Constants.nav_menu_music 56 | musicFragment.selectFirstItem() 57 | } 58 | Constants.nav_menu_news -> { 59 | currentSelectedFragment = Constants.nav_menu_news 60 | newsFragment.selectFirstItem() 61 | } 62 | Constants.nav_menu_podcasts -> { 63 | currentSelectedFragment = Constants.nav_menu_podcasts 64 | podcastsFragment.selectFirstItem() 65 | } 66 | Constants.nav_menu_settings -> { 67 | currentSelectedFragment = Constants.nav_menu_settings 68 | settingsFragment.selectFirstItem() 69 | } 70 | } 71 | } else { 72 | //do 73 | } 74 | } 75 | 76 | override fun switchFragment(fragmentName: String?) { 77 | nav_fragment.setBackgroundResource(R.drawable.ic_nav_bg_closed) 78 | when (fragmentName) { 79 | Constants.nav_menu_movies -> { 80 | moviesFragment = MoviesFragment() 81 | fragmentReplacer(main_FL.id, MoviesFragment()) 82 | moviesFragment.restoreSelection() 83 | } 84 | Constants.nav_menu_news -> { 85 | newsFragment = NewsFragment() 86 | fragmentReplacer(main_FL.id, newsFragment) 87 | newsFragment.selectFirstItem() 88 | } 89 | Constants.nav_menu_music -> { 90 | musicFragment = MusicFragment() 91 | fragmentReplacer(main_FL.id, musicFragment) 92 | musicFragment.selectFirstItem() 93 | } 94 | Constants.nav_menu_shows -> { 95 | showsFragment = ShowsFragment() 96 | fragmentReplacer(main_FL.id, showsFragment) 97 | showsFragment.selectFirstItem() 98 | } 99 | Constants.nav_menu_settings -> { 100 | settingsFragment = SettingsFragment() 101 | fragmentReplacer(main_FL.id, settingsFragment) 102 | settingsFragment.selectFirstItem() 103 | } 104 | Constants.nav_menu_podcasts -> { 105 | podcastsFragment = PodcastsFragment() 106 | fragmentReplacer(main_FL.id, podcastsFragment) 107 | podcastsFragment.selectFirstItem() 108 | } 109 | } 110 | } 111 | 112 | override fun navMenuToggle(toShow: Boolean) { 113 | 114 | try { 115 | if (toShow) { 116 | nav_fragment.setBackgroundResource(R.drawable.ic_nav_bg_open) 117 | main_FL.clearFocus() 118 | nav_fragment.requestFocus() 119 | navEnterAnimation() 120 | navMenuFragment.openNav() 121 | } else { 122 | nav_fragment.setBackgroundResource(R.drawable.ic_nav_bg_closed) 123 | nav_fragment.clearFocus() 124 | main_FL.requestFocus() 125 | navMenuFragment.closeNav() 126 | } 127 | } catch (e: Exception) { 128 | e.printStackTrace() 129 | } 130 | } 131 | 132 | override fun onAttachFragment(fragment: Fragment) { 133 | 134 | when(fragment) { 135 | is MoviesFragment -> { 136 | fragment.setNavigationMenuCallback(this) 137 | } 138 | is NewsFragment -> { 139 | fragment.setNavigationMenuCallback(this) 140 | } 141 | is MusicFragment -> { 142 | fragment.setNavigationMenuCallback(this) 143 | } 144 | is SettingsFragment -> { 145 | fragment.setNavigationMenuCallback(this) 146 | } 147 | is PodcastsFragment -> { 148 | fragment.setNavigationMenuCallback(this) 149 | } 150 | is ShowsFragment -> { 151 | fragment.setNavigationMenuCallback(this) 152 | } 153 | is NavigationMenu -> { 154 | fragment.setFragmentChangeListener(this) 155 | fragment.setNavigationStateListener(this) 156 | } 157 | } 158 | 159 | } 160 | 161 | private fun navEnterAnimation() { 162 | val animate = AnimationUtils.loadAnimation(this, R.anim.slide_in_left) 163 | nav_fragment.startAnimation(animate) 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/AbstractCardPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | 4 | 5 | import android.content.Context 6 | import android.view.ViewGroup 7 | import androidx.leanback.widget.BaseCardView 8 | import androidx.leanback.widget.Presenter 9 | 10 | /** 11 | * This abstract, generic class will create and manage the 12 | * ViewHolder and will provide typed Presenter callbacks such that you do not have to perform casts 13 | * on your own. 14 | * 15 | * @param View type for the card. 16 | */ 17 | abstract class AbstractCardPresenter 18 | /** 19 | * @param context The current context. 20 | */(val context: Context) : 21 | Presenter() { 22 | 23 | override fun onCreateViewHolder(parent: ViewGroup): ViewHolder { 24 | val cardView = onCreateView() 25 | return ViewHolder(cardView) 26 | } 27 | 28 | override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) { 29 | onBindViewHolder(item, viewHolder.view as T) 30 | } 31 | 32 | override fun onUnbindViewHolder(viewHolder: ViewHolder) { 33 | onUnbindViewHolder(viewHolder.view as T) 34 | } 35 | 36 | fun onUnbindViewHolder(cardView: T) { 37 | // Nothing to clean up. Override if necessary. 38 | } 39 | 40 | /** 41 | * Invoked when a new view is created. 42 | * 43 | * @return Returns the newly created view. 44 | */ 45 | protected abstract fun onCreateView(): T 46 | 47 | abstract fun onBindViewHolder(card: Any, cardView: T) 48 | 49 | companion object { 50 | private const val TAG = "AbstractCardPresenter" 51 | } 52 | 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/CardListRow.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import androidx.leanback.widget.HeaderItem 4 | import androidx.leanback.widget.ListRow 5 | import androidx.leanback.widget.ObjectAdapter 6 | 7 | class CardListRow(header: HeaderItem, adapter: ObjectAdapter) : 8 | ListRow(header, adapter) 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/CardPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.content.Context 4 | import androidx.leanback.widget.Presenter 5 | 6 | 7 | 8 | import android.view.Gravity 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.widget.TextView 12 | import androidx.appcompat.widget.AppCompatImageView 13 | import androidx.constraintlayout.widget.ConstraintLayout 14 | import androidx.leanback.widget.BaseCardView 15 | import com.androijo.sample.R 16 | import com.bumptech.glide.Glide 17 | 18 | /** 19 | * This Presenter will display a card consisting of an image on the left side of the card followed 20 | * by text on the right side. The image and text have equal width. The text will work like a info 21 | * box, thus it will be hidden if the parent row is inactive. This behavior is unique to this card 22 | * and requires a special focus handler. 23 | */ 24 | class CardPresenter(context: Context) : 25 | AbstractCardPresenter(context) { 26 | 27 | override fun onCreateView(): BaseCardView { 28 | val cardView = BaseCardView(context, null, R.style.Widget_Leanback_BaseCardViewStyle) 29 | cardView.isFocusable = true 30 | cardView.addView(LayoutInflater.from(context).inflate(R.layout.card_subject, null, false)) 31 | return cardView 32 | } 33 | 34 | override fun onBindViewHolder(card: Any, cardView: BaseCardView) { 35 | val data = card as String 36 | val textView = cardView.findViewById(R.id.cardName) 37 | textView.text = data 38 | 39 | } 40 | 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/CardPresenterSelector.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import androidx.leanback.widget.Presenter 6 | import androidx.leanback.widget.PresenterSelector 7 | 8 | class CardPresenterSelector(private val mContext: Context) : PresenterSelector() { 9 | 10 | override fun getPresenter(item: Any?): Presenter? { 11 | return CardPresenter(mContext) 12 | } 13 | 14 | override fun getPresenters(): Array { 15 | return super.getPresenters() 16 | } 17 | 18 | } 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/MoviesFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.KeyEvent 6 | import android.view.View 7 | import androidx.leanback.app.RowsSupportFragment 8 | import androidx.leanback.widget.* 9 | import com.androijo.sample.R 10 | import com.androijo.sample.interfaces.NavigationMenuCallback 11 | 12 | 13 | class MoviesFragment : RowsSupportFragment() { 14 | 15 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 16 | 17 | private lateinit var navigationMenuCallback: NavigationMenuCallback 18 | private val dataList = ArrayList() 19 | 20 | init { 21 | initAdapters() 22 | initListeners() 23 | } 24 | 25 | private fun initAdapters() { 26 | adapter = mRowsAdapter 27 | } 28 | 29 | private fun initListeners() { 30 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 31 | val indexOfRow = mRowsAdapter.indexOf(row) 32 | 33 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 34 | 35 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 36 | if (event.action == KeyEvent.ACTION_DOWN) { 37 | when (keyCode) { 38 | KeyEvent.KEYCODE_DPAD_LEFT -> { 39 | if (indexOfItem == 0) { 40 | navigationMenuCallback.navMenuToggle(true) 41 | } 42 | } 43 | } 44 | } 45 | false 46 | } 47 | } 48 | } 49 | 50 | override fun onCreate(savedInstanceState: Bundle?) { 51 | super.onCreate(savedInstanceState) 52 | dataList.add("1") 53 | dataList.add("2") 54 | dataList.add("3") 55 | dataList.add("4") 56 | dataList.add("5") 57 | } 58 | 59 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 60 | super.onViewCreated(view, savedInstanceState) 61 | createRows() 62 | } 63 | 64 | private fun createRows() { 65 | for(rowIndex in 1..5){ 66 | mRowsAdapter.add(createNewRow(rowIndex)) 67 | } 68 | } 69 | 70 | private fun createNewRow(rowIndex: Int): Row { 71 | val presenterSelector = activity?.baseContext?.let { 72 | CardPresenterSelector(it) 73 | } 74 | val adapter = ArrayObjectAdapter(presenterSelector) 75 | for (data in dataList) { 76 | adapter.add(data) 77 | } 78 | val headerItem = HeaderItem("${getString(R.string.Movies)} Row $rowIndex") 79 | return CardListRow(headerItem, adapter) 80 | } 81 | 82 | 83 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 84 | this.navigationMenuCallback = callback 85 | } 86 | 87 | /** 88 | * this function can put focus or select a specific item in a specific row 89 | */ 90 | fun restoreSelection() { 91 | setSelectedPosition( 92 | 0, 93 | true, 94 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 95 | override fun run(holder: Presenter.ViewHolder?) { 96 | super.run(holder) 97 | holder?.view?.postDelayed({ 98 | holder.view.requestFocus() 99 | }, 10) 100 | } 101 | }) 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/MusicFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.leanback.app.RowsSupportFragment 7 | import androidx.leanback.widget.* 8 | import com.androijo.sample.R 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | 11 | class MusicFragment : RowsSupportFragment() { 12 | 13 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 14 | 15 | private lateinit var navigationMenuCallback: NavigationMenuCallback 16 | private val dataList = ArrayList() 17 | 18 | init { 19 | initAdapters() 20 | initListeners() 21 | } 22 | 23 | private fun initAdapters() { 24 | adapter = mRowsAdapter 25 | } 26 | 27 | private fun initListeners() { 28 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 29 | val indexOfRow = mRowsAdapter.indexOf(row) 30 | 31 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 32 | 33 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 34 | if (event.action == KeyEvent.ACTION_DOWN) { 35 | when (keyCode) { 36 | KeyEvent.KEYCODE_DPAD_LEFT -> { 37 | if (indexOfItem == 0) { 38 | navigationMenuCallback.navMenuToggle(true) 39 | } 40 | } 41 | } 42 | } 43 | false 44 | } 45 | } 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | dataList.add("1") 51 | dataList.add("2") 52 | dataList.add("3") 53 | dataList.add("4") 54 | dataList.add("5") 55 | } 56 | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 | super.onViewCreated(view, savedInstanceState) 59 | createRows() 60 | } 61 | 62 | private fun createRows() { 63 | for(rowIndex in 1..5){ 64 | mRowsAdapter.add(createNewRow(rowIndex)) 65 | } 66 | } 67 | 68 | private fun createNewRow(rowIndex: Int): Row { 69 | val presenterSelector = activity?.baseContext?.let { 70 | CardPresenterSelector(it) 71 | } 72 | val adapter = ArrayObjectAdapter(presenterSelector) 73 | for (data in dataList) { 74 | adapter.add(data) 75 | } 76 | val headerItem = HeaderItem("${getString(R.string.Music)} Row $rowIndex") 77 | return CardListRow(headerItem, adapter) 78 | } 79 | 80 | 81 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 82 | this.navigationMenuCallback = callback 83 | } 84 | 85 | 86 | /** 87 | * this function can put focus or selected a specific item in a specific row 88 | */ 89 | 90 | fun selectFirstItem() { 91 | setSelectedPosition( 92 | 0, 93 | true, 94 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 95 | override fun run(holder: Presenter.ViewHolder?) { 96 | super.run(holder) 97 | holder?.view?.postDelayed({ 98 | holder.view.requestFocus() 99 | }, 10) 100 | } 101 | }) 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/NewsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.leanback.app.RowsSupportFragment 7 | import androidx.leanback.widget.* 8 | import com.androijo.sample.R 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | 11 | class NewsFragment : RowsSupportFragment() { 12 | 13 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 14 | 15 | private lateinit var navigationMenuCallback: NavigationMenuCallback 16 | private val dataList = ArrayList() 17 | 18 | init { 19 | initAdapters() 20 | initListeners() 21 | } 22 | 23 | private fun initAdapters() { 24 | adapter = mRowsAdapter 25 | } 26 | 27 | private fun initListeners() { 28 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 29 | val indexOfRow = mRowsAdapter.indexOf(row) 30 | 31 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 32 | 33 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 34 | if (event.action == KeyEvent.ACTION_DOWN) { 35 | when (keyCode) { 36 | KeyEvent.KEYCODE_DPAD_LEFT -> { 37 | if (indexOfItem == 0) { 38 | navigationMenuCallback.navMenuToggle(true) 39 | } 40 | } 41 | } 42 | } 43 | false 44 | } 45 | } 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | dataList.add("1") 51 | dataList.add("2") 52 | dataList.add("3") 53 | dataList.add("4") 54 | dataList.add("5") 55 | } 56 | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 | super.onViewCreated(view, savedInstanceState) 59 | createRows() 60 | } 61 | 62 | private fun createRows() { 63 | for(rowIndex in 1..5){ 64 | mRowsAdapter.add(createNewRow(rowIndex)) 65 | } 66 | } 67 | 68 | private fun createNewRow(rowIndex: Int): Row { 69 | val presenterSelector = activity?.baseContext?.let { 70 | CardPresenterSelector(it) 71 | } 72 | val adapter = ArrayObjectAdapter(presenterSelector) 73 | for (data in dataList) { 74 | adapter.add(data) 75 | } 76 | val headerItem = HeaderItem("${getString(R.string.News)} Row $rowIndex") 77 | return CardListRow(headerItem, adapter) 78 | } 79 | 80 | 81 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 82 | this.navigationMenuCallback = callback 83 | } 84 | 85 | /** 86 | * this function can put focus or selected a specific item in a specific row 87 | */ 88 | 89 | fun selectFirstItem() { 90 | setSelectedPosition( 91 | 0, 92 | true, 93 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 94 | override fun run(holder: Presenter.ViewHolder?) { 95 | super.run(holder) 96 | holder?.view?.postDelayed({ 97 | holder.view.requestFocus() 98 | }, 10) 99 | } 100 | }) 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/PodcastsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.leanback.app.RowsSupportFragment 7 | import androidx.leanback.widget.* 8 | import com.androijo.sample.R 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | 11 | class PodcastsFragment : RowsSupportFragment() { 12 | 13 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 14 | 15 | private lateinit var navigationMenuCallback: NavigationMenuCallback 16 | private val dataList = ArrayList() 17 | 18 | init { 19 | initAdapters() 20 | initListeners() 21 | } 22 | 23 | private fun initAdapters() { 24 | adapter = mRowsAdapter 25 | } 26 | 27 | private fun initListeners() { 28 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 29 | val indexOfRow = mRowsAdapter.indexOf(row) 30 | 31 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 32 | 33 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 34 | if (event.action == KeyEvent.ACTION_DOWN) { 35 | when (keyCode) { 36 | KeyEvent.KEYCODE_DPAD_LEFT -> { 37 | if (indexOfItem == 0) { 38 | navigationMenuCallback.navMenuToggle(true) 39 | } 40 | } 41 | } 42 | } 43 | false 44 | } 45 | } 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | dataList.add("1") 51 | dataList.add("2") 52 | dataList.add("3") 53 | dataList.add("4") 54 | dataList.add("5") 55 | } 56 | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 | super.onViewCreated(view, savedInstanceState) 59 | createRows() 60 | } 61 | 62 | private fun createRows() { 63 | for(rowIndex in 1..5){ 64 | mRowsAdapter.add(createNewRow(rowIndex)) 65 | } 66 | } 67 | 68 | private fun createNewRow(rowIndex: Int): Row { 69 | val presenterSelector = activity?.baseContext?.let { 70 | CardPresenterSelector(it) 71 | } 72 | val adapter = ArrayObjectAdapter(presenterSelector) 73 | for (data in dataList) { 74 | adapter.add(data) 75 | } 76 | val headerItem = HeaderItem("${getString(R.string.PodCasts)} Row $rowIndex") 77 | return CardListRow(headerItem, adapter) 78 | } 79 | 80 | 81 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 82 | this.navigationMenuCallback = callback 83 | } 84 | 85 | 86 | /** 87 | * this function can put focus or selected a specific item in a specific row 88 | */ 89 | 90 | fun selectFirstItem() { 91 | setSelectedPosition( 92 | 0, 93 | true, 94 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 95 | override fun run(holder: Presenter.ViewHolder?) { 96 | super.run(holder) 97 | holder?.view?.postDelayed({ 98 | holder.view.requestFocus() 99 | }, 10) 100 | } 101 | }) 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/RowPresenterSelector.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import androidx.leanback.widget.FocusHighlight 4 | import androidx.leanback.widget.ListRowPresenter 5 | import androidx.leanback.widget.Presenter 6 | import androidx.leanback.widget.PresenterSelector 7 | 8 | class RowPresenterSelector : PresenterSelector() { 9 | 10 | val customListRowPresenter = object : ListRowPresenter(FocusHighlight.ZOOM_FACTOR_LARGE, false) { 11 | override fun isUsingDefaultListSelectEffect() = false 12 | override fun isUsingDefaultShadow(): Boolean { 13 | return false 14 | } 15 | 16 | }.apply { 17 | shadowEnabled = false 18 | } 19 | 20 | 21 | private val mShadowEnabledRowPresenter = customListRowPresenter 22 | private val mShadowDisabledRowPresenter = customListRowPresenter 23 | 24 | init { 25 | mShadowEnabledRowPresenter.setNumRows(1) 26 | mShadowDisabledRowPresenter.shadowEnabled = true 27 | } 28 | 29 | override fun getPresenter(item: Any): Presenter { 30 | 31 | if (item !is CardListRow) return mShadowDisabledRowPresenter 32 | return mShadowDisabledRowPresenter 33 | } 34 | 35 | override fun getPresenters(): Array { 36 | return arrayOf(mShadowDisabledRowPresenter, mShadowEnabledRowPresenter) 37 | } 38 | 39 | fun getListRowPresenter(): ListRowPresenter = customListRowPresenter 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.leanback.app.RowsSupportFragment 7 | import androidx.leanback.widget.* 8 | import com.androijo.sample.R 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | 11 | class SettingsFragment : RowsSupportFragment() { 12 | 13 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 14 | 15 | private lateinit var navigationMenuCallback: NavigationMenuCallback 16 | private val dataList = ArrayList() 17 | 18 | init { 19 | initAdapters() 20 | initListeners() 21 | } 22 | 23 | private fun initAdapters() { 24 | adapter = mRowsAdapter 25 | } 26 | 27 | private fun initListeners() { 28 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 29 | val indexOfRow = mRowsAdapter.indexOf(row) 30 | 31 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 32 | 33 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 34 | if (event.action == KeyEvent.ACTION_DOWN) { 35 | when (keyCode) { 36 | KeyEvent.KEYCODE_DPAD_LEFT -> { 37 | if (indexOfItem == 0) { 38 | navigationMenuCallback.navMenuToggle(true) 39 | } 40 | } 41 | } 42 | } 43 | false 44 | } 45 | } 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | dataList.add("1") 51 | dataList.add("2") 52 | dataList.add("3") 53 | dataList.add("4") 54 | dataList.add("5") 55 | } 56 | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 | super.onViewCreated(view, savedInstanceState) 59 | createRows() 60 | } 61 | 62 | private fun createRows() { 63 | for(rowIndex in 1..5){ 64 | mRowsAdapter.add(createNewRow(rowIndex)) 65 | } 66 | } 67 | 68 | private fun createNewRow(rowIndex: Int): Row { 69 | val presenterSelector = activity?.baseContext?.let { 70 | CardPresenterSelector(it) 71 | } 72 | val adapter = ArrayObjectAdapter(presenterSelector) 73 | for (data in dataList) { 74 | adapter.add(data) 75 | } 76 | val headerItem = HeaderItem("${getString(R.string.Settings)} Row $rowIndex") 77 | return CardListRow(headerItem, adapter) 78 | } 79 | 80 | 81 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 82 | this.navigationMenuCallback = callback 83 | } 84 | /** 85 | * this function can put focus or selected a specific item in a specific row 86 | */ 87 | 88 | fun selectFirstItem() { 89 | setSelectedPosition( 90 | 0, 91 | true, 92 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 93 | override fun run(holder: Presenter.ViewHolder?) { 94 | super.run(holder) 95 | holder?.view?.postDelayed({ 96 | holder.view.requestFocus() 97 | }, 10) 98 | } 99 | }) 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/fragments/ShowsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.leanback.app.RowsSupportFragment 7 | import androidx.leanback.widget.* 8 | import com.androijo.sample.R 9 | import com.androijo.sample.interfaces.NavigationMenuCallback 10 | 11 | class ShowsFragment : RowsSupportFragment() { 12 | 13 | private var mRowsAdapter: ArrayObjectAdapter = ArrayObjectAdapter(RowPresenterSelector()) 14 | 15 | private lateinit var navigationMenuCallback: NavigationMenuCallback 16 | private val dataList = ArrayList() 17 | 18 | init { 19 | initAdapters() 20 | initListeners() 21 | } 22 | 23 | private fun initAdapters() { 24 | adapter = mRowsAdapter 25 | } 26 | 27 | private fun initListeners() { 28 | onItemViewSelectedListener = OnItemViewSelectedListener {itemViewHolder, item, rowViewHolder, row -> 29 | val indexOfRow = mRowsAdapter.indexOf(row) 30 | 31 | val indexOfItem = ((row as CardListRow).adapter as ArrayObjectAdapter).indexOf(item) 32 | 33 | itemViewHolder?.view?.setOnKeyListener { v, keyCode, event -> 34 | if (event.action == KeyEvent.ACTION_DOWN) { 35 | when (keyCode) { 36 | KeyEvent.KEYCODE_DPAD_LEFT -> { 37 | if (indexOfItem == 0) { 38 | navigationMenuCallback.navMenuToggle(true) 39 | } 40 | } 41 | } 42 | } 43 | false 44 | } 45 | } 46 | } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | dataList.add("1") 51 | dataList.add("2") 52 | dataList.add("3") 53 | dataList.add("4") 54 | dataList.add("5") 55 | } 56 | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 | super.onViewCreated(view, savedInstanceState) 59 | createRows() 60 | } 61 | 62 | private fun createRows() { 63 | for(rowIndex in 1..5){ 64 | mRowsAdapter.add(createNewRow(rowIndex)) 65 | } 66 | } 67 | 68 | private fun createNewRow(rowIndex: Int): Row { 69 | val presenterSelector = activity?.baseContext?.let { 70 | CardPresenterSelector(it) 71 | } 72 | val adapter = ArrayObjectAdapter(presenterSelector) 73 | for (data in dataList) { 74 | adapter.add(data) 75 | } 76 | val headerItem = HeaderItem("${getString(R.string.Shows)} Row $rowIndex") 77 | return CardListRow(headerItem, adapter) 78 | } 79 | 80 | 81 | fun setNavigationMenuCallback(callback: NavigationMenuCallback) { 82 | this.navigationMenuCallback = callback 83 | } 84 | 85 | /** 86 | * this function can put focus or selected a specific item in a specific row 87 | */ 88 | 89 | fun selectFirstItem() { 90 | setSelectedPosition( 91 | 0, 92 | true, 93 | object : ListRowPresenter.SelectItemViewHolderTask(0) { 94 | override fun run(holder: Presenter.ViewHolder?) { 95 | super.run(holder) 96 | holder?.view?.postDelayed({ 97 | holder.view.requestFocus() 98 | }, 10) 99 | } 100 | }) 101 | } 102 | } -------------------------------------------------------------------------------- /app/src/main/java/com/androijo/sample/interfaces/NavigationMenuCallback.kt: -------------------------------------------------------------------------------- 1 | package com.androijo.sample.interfaces 2 | 3 | interface NavigationMenuCallback { 4 | fun navMenuToggle(toShow: Boolean) 5 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_icon_your_company.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arpit0492/TVNavigationMenu/c996b7fc71534c2b63ae6ba440a281a7f437a842/app/src/main/res/drawable/app_icon_your_company.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_nav_bg_closed.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_nav_bg_open.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_sample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 21 | 22 | 33 | 34 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/card_subject.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #000000 3 | #DDDDDD 4 | #0096a6 5 | #ffaa3f 6 | #ffaa3f 7 | #3d3d3d 8 | #A9421C 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 150dp 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | TV Menu Navigation 3 | Videos by Your Company 4 | Related Videos 5 | Grid View 6 | Error Fragment 7 | Personal Settings 8 | Watch trailer 9 | FREE 10 | Rent By Day 11 | From $1.99 12 | Buy and Own 13 | AT $9.99 14 | Movie 15 | 16 | 17 | An error occurred 18 | Dismiss 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |