├── .gitignore ├── README.md ├── app ├── App_Resources │ ├── Android │ │ ├── AndroidManifest.xml │ │ ├── app.gradle │ │ ├── drawable-hdpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── drawable-ldpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── drawable-mdpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── drawable-nodpi │ │ │ ├── banner.png │ │ │ ├── bluebutton.xml │ │ │ ├── bluebutton_focused.xml │ │ │ ├── navbutton.xml │ │ │ └── splash_screen.xml │ │ ├── drawable-xhdpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── drawable-xxhdpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── drawable-xxxhdpi │ │ │ ├── background.png │ │ │ ├── icon.png │ │ │ └── logo.png │ │ ├── values-v21 │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ └── values │ │ │ ├── colors.xml │ │ │ └── styles.xml │ └── iOS │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-29.png │ │ │ ├── icon-29@2x.png │ │ │ ├── icon-29@3x.png │ │ │ ├── icon-40.png │ │ │ ├── icon-40@2x.png │ │ │ ├── icon-40@3x.png │ │ │ ├── icon-50.png │ │ │ ├── icon-50@2x.png │ │ │ ├── icon-57.png │ │ │ ├── icon-57@2x.png │ │ │ ├── icon-60@2x.png │ │ │ ├── icon-60@3x.png │ │ │ ├── icon-72.png │ │ │ ├── icon-72@2x.png │ │ │ ├── icon-76.png │ │ │ ├── icon-76@2x.png │ │ │ └── icon-83.5@2x.png │ │ ├── Contents.json │ │ ├── LaunchImage.launchimage │ │ │ ├── Contents.json │ │ │ ├── Default-568h@2x.png │ │ │ ├── Default-667h@2x.png │ │ │ ├── Default-736h@3x.png │ │ │ ├── Default-Landscape.png │ │ │ ├── Default-Landscape@2x.png │ │ │ ├── Default-Landscape@3x.png │ │ │ ├── Default-Portrait.png │ │ │ ├── Default-Portrait@2x.png │ │ │ ├── Default.png │ │ │ └── Default@2x.png │ │ ├── LaunchScreen.AspectFill.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchScreen-AspectFill.png │ │ │ └── LaunchScreen-AspectFill@2x.png │ │ └── LaunchScreen.Center.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchScreen-Center.png │ │ │ └── LaunchScreen-Center@2x.png │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── build.xcconfig ├── app.css ├── app.ts ├── main-page-tv.css ├── main-page-tv.ts ├── main-page-tv.xml ├── main-page.ts ├── main-page.xml ├── main-view-model.ts ├── package.json ├── vendor-platform.android.ts ├── vendor-platform.ios.ts └── vendor.ts ├── package-lock.json ├── package.json ├── references.d.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | platforms/ 4 | hooks/ 5 | *.js 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NativeScript ❤️ Android TV 2 | 3 | * [YouTube video of this app, running on a Phone and TV (23s)](https://www.youtube.com/watch?v=b9Wv0IzN3ts) 4 | * [YouTube video if this app, running on a TV, with D-Pad controls (20s)](https://www.youtube.com/watch?v=HjxvDxbAOW0) 5 | 6 | ### What? 7 | Unsurprisingly Android TV is very much like the Android you know and love, 8 | and since NativeScript already runs like a champ on Android, you can easily 9 | support Android TV as well! 10 | 11 | ### How?! 12 | I found the easiest way to support TV devices is adding [this line](https://github.com/EddyVerbruggen/nativescript-android-tv/blob/3b3201e979bff762cc4bc36ad04eb946cb48bd6d/app/App_Resources/Android/AndroidManifest.xml#L48) to your `AndroidManifest.xml` 13 | and [figuring out at runtime which UI to load](https://github.com/EddyVerbruggen/nativescript-android-tv/blob/db3848abc508d700ecb80e320c5e5374b1f2073b/app/app.ts#L6-L19). 14 | 15 | #### Wait.. does that mean I have to duplicate code? 16 | You don't *have* to duplicate anything, but you really don't want to reuse phone layouts on your TV 17 | for obvious reasons. So what this PoC does, is using a `main-page.xml` for Phone / Tablet, and `main-page-tv.xml` 18 | for TV to accomodate for the additional screen real estate - but they share the same `main-view-model.ts`. 19 | 20 | ### Can I use Angular or Vue as well? 21 | Sure you can, as those eventually render the same UI widgets as regular NativeScript does. 22 | 23 | ### And what about iOS? 24 | Nothing special there - iOS is powered by the same code that makes the Android Phone / Tablet version tick. 25 | 26 | #### Sorry, I meant Apple TV 27 | Ah, OK, ehm, please refer to [this blog](https://www.nativescript.org/blog/running-the-nativescript-runtime-for-ios-on-apple-tv). 28 | 29 | ### Lemme try 30 | Create an Android TV emulator with the AVD manager inside Android Studio (if you're not so lucky to own a real device), then: 31 | 32 | ```bash 33 | git clone https://github.com/EddyVerbruggen/nativescript-android-tv 34 | cd nativescript-android-tv 35 | npm i 36 | tns run android 37 | ``` 38 | -------------------------------------------------------------------------------- /app/App_Resources/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 17 | 18 | 19 | 20 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/App_Resources/Android/app.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile 'com.android.support:appcompat-v7:25+' 3 | // compile 'com.android.support:leanback-v17:+' 4 | } 5 | 6 | android { 7 | defaultConfig { 8 | generatedDensities = [] 9 | applicationId = "org.nativescript.sample.androidtv" 10 | } 11 | aaptOptions { 12 | additionalParameters "--no-version-vectors" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-hdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-hdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-ldpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-ldpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-mdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-mdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-nodpi/banner.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/bluebutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/bluebutton_focused.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/navbutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxxhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/Android/drawable-xxxhdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/values-v21/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3d5afe 4 | -------------------------------------------------------------------------------- /app/App_Resources/Android/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 14 | 15 | 16 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /app/App_Resources/Android/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F5F5F5 4 | #757575 5 | #33B5E5 6 | #272734 7 | -------------------------------------------------------------------------------- /app/App_Resources/Android/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | 21 | 22 | 23 | 31 | 32 | 34 | 35 | 36 | 42 | 43 | 45 | 46 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "icon-29.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "icon-29@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@3x.png", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "icon-40@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "57x57", 35 | "idiom" : "iphone", 36 | "filename" : "icon-57.png", 37 | "scale" : "1x" 38 | }, 39 | { 40 | "size" : "57x57", 41 | "idiom" : "iphone", 42 | "filename" : "icon-57@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon-60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "icon-60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "29x29", 59 | "idiom" : "ipad", 60 | "filename" : "icon-29.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "icon-29@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "40x40", 71 | "idiom" : "ipad", 72 | "filename" : "icon-40.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "icon-40@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "50x50", 83 | "idiom" : "ipad", 84 | "filename" : "icon-50.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "50x50", 89 | "idiom" : "ipad", 90 | "filename" : "icon-50@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "72x72", 95 | "idiom" : "ipad", 96 | "filename" : "icon-72.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "72x72", 101 | "idiom" : "ipad", 102 | "filename" : "icon-72@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "76x76", 107 | "idiom" : "ipad", 108 | "filename" : "icon-76.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "76x76", 113 | "idiom" : "ipad", 114 | "filename" : "icon-76@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "83.5x83.5", 119 | "idiom" : "ipad", 120 | "filename" : "icon-83.5@2x.png", 121 | "scale" : "2x" 122 | } 123 | ], 124 | "info" : { 125 | "version" : 1, 126 | "author" : "xcode" 127 | } 128 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-736h@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-Landscape@3x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-667h@2x.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "orientation" : "portrait", 49 | "idiom" : "ipad", 50 | "filename" : "Default-Portrait.png", 51 | "extent" : "full-screen", 52 | "minimum-system-version" : "7.0", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "orientation" : "landscape", 57 | "idiom" : "ipad", 58 | "filename" : "Default-Landscape.png", 59 | "extent" : "full-screen", 60 | "minimum-system-version" : "7.0", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "filename" : "Default-Portrait@2x.png", 67 | "extent" : "full-screen", 68 | "minimum-system-version" : "7.0", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "orientation" : "landscape", 73 | "idiom" : "ipad", 74 | "filename" : "Default-Landscape@2x.png", 75 | "extent" : "full-screen", 76 | "minimum-system-version" : "7.0", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "orientation" : "portrait", 81 | "idiom" : "iphone", 82 | "filename" : "Default.png", 83 | "extent" : "full-screen", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "orientation" : "portrait", 88 | "idiom" : "iphone", 89 | "filename" : "Default@2x.png", 90 | "extent" : "full-screen", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "orientation" : "portrait", 95 | "idiom" : "iphone", 96 | "filename" : "Default-568h@2x.png", 97 | "extent" : "full-screen", 98 | "subtype" : "retina4", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "orientation" : "portrait", 103 | "idiom" : "ipad", 104 | "extent" : "to-status-bar", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "orientation" : "portrait", 109 | "idiom" : "ipad", 110 | "filename" : "Default-Portrait.png", 111 | "extent" : "full-screen", 112 | "scale" : "1x" 113 | }, 114 | { 115 | "orientation" : "landscape", 116 | "idiom" : "ipad", 117 | "extent" : "to-status-bar", 118 | "scale" : "1x" 119 | }, 120 | { 121 | "orientation" : "landscape", 122 | "idiom" : "ipad", 123 | "filename" : "Default-Landscape.png", 124 | "extent" : "full-screen", 125 | "scale" : "1x" 126 | }, 127 | { 128 | "orientation" : "portrait", 129 | "idiom" : "ipad", 130 | "extent" : "to-status-bar", 131 | "scale" : "2x" 132 | }, 133 | { 134 | "orientation" : "portrait", 135 | "idiom" : "ipad", 136 | "filename" : "Default-Portrait@2x.png", 137 | "extent" : "full-screen", 138 | "scale" : "2x" 139 | }, 140 | { 141 | "orientation" : "landscape", 142 | "idiom" : "ipad", 143 | "extent" : "to-status-bar", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "filename" : "Default-Landscape@2x.png", 150 | "extent" : "full-screen", 151 | "scale" : "2x" 152 | } 153 | ], 154 | "info" : { 155 | "version" : 1, 156 | "author" : "xcode" 157 | } 158 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-AspectFill.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-AspectFill@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-Center.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-Center@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EddyVerbruggen/nativescript-android-tv/1238aa0654d9fbba00cc4d373af8d84127b1014b/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiresFullScreen 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/build.xcconfig: -------------------------------------------------------------------------------- 1 | // You can add custom settings here 2 | // for example you can uncomment the following line to force distribution code signing 3 | // CODE_SIGN_IDENTITY = iPhone Distribution 4 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 5 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 6 | DEVELOPMENT_TEAM = 8Q5F6M3TNS 7 | -------------------------------------------------------------------------------- /app/app.css: -------------------------------------------------------------------------------- 1 | Label { 2 | color: #666; 3 | text-align: center; 4 | } 5 | 6 | Label.message { 7 | font-size: 16; 8 | padding: 20; 9 | } 10 | 11 | button { 12 | background-color: #87cefa; 13 | padding: 3; 14 | margin: 8; 15 | font-size: 14; 16 | border-radius: 5; 17 | } 18 | 19 | .button { 20 | color: #ffffff; 21 | } 22 | 23 | .button-a { 24 | background-color: #90A959; 25 | } 26 | 27 | .button-b { 28 | background-color: #E0A458; 29 | } 30 | 31 | .button-c { 32 | background-color: #64A4FF; 33 | } 34 | 35 | .button-d { 36 | background-color: #22B4CC; 37 | } 38 | 39 | Label.hint { 40 | padding-top: 10; 41 | font-size: 13; 42 | } -------------------------------------------------------------------------------- /app/app.ts: -------------------------------------------------------------------------------- 1 | import * as application from "tns-core-modules/application"; 2 | import * as utils from "tns-core-modules/utils/utils"; 3 | import * as frame from "tns-core-modules/ui/frame"; 4 | import { ViewBase } from "tns-core-modules/ui/core/view-base"; 5 | 6 | if (utils.ad) { 7 | // Android: Load either the TV or phone UI 8 | const uiModeManager = utils.ad.getApplicationContext().getSystemService(android.content.Context.UI_MODE_SERVICE); 9 | if (uiModeManager.getCurrentModeType() === android.content.res.Configuration.UI_MODE_TYPE_TELEVISION) { 10 | console.log("Running on a TV"); 11 | application.start({moduleName: "main-page-tv"}); 12 | } else { 13 | console.log("Running on a Phone / Tablet"); 14 | application.start({moduleName: "main-page"}); 15 | } 16 | } else { 17 | // iOS 18 | application.start({moduleName: "main-page"}); 19 | } 20 | 21 | 22 | // The class below is not currently used (also commented in AndroidManifest.xml) 23 | @JavaProxy("com.tns.NativeScriptTVActivity") 24 | class Activity extends android.app.Activity { 25 | private _callbacks: frame.AndroidActivityCallbacks; 26 | 27 | private highlightedElement: ViewBase; 28 | 29 | onCreate(savedInstanceState: android.os.Bundle): void { 30 | if (!this._callbacks) { 31 | (frame).setActivityCallbacks(this); 32 | } 33 | this._callbacks.onCreate(this, savedInstanceState, super.onCreate); 34 | } 35 | 36 | protected onSaveInstanceState(outState: android.os.Bundle): void { 37 | this._callbacks.onSaveInstanceState(this, outState, super.onSaveInstanceState); 38 | } 39 | 40 | protected onStart(): void { 41 | this._callbacks.onStart(this, super.onStart); 42 | } 43 | 44 | protected onStop(): void { 45 | this._callbacks.onStop(this, super.onStop); 46 | } 47 | 48 | protected onDestroy(): void { 49 | this._callbacks.onDestroy(this, super.onDestroy); 50 | } 51 | 52 | public dispatchKeyEvent(event: android.view.KeyEvent): boolean { 53 | // you can respond to specific keycodes by fi. registering a listener and invoking it when appropriate 54 | console.log("D-Pad center button pressed? " + (event.getKeyCode() === android.view.KeyEvent.KEYCODE_DPAD_CENTER)); 55 | 56 | // let's highlight the element that currently has the focus 57 | const tnsButton = this.getCurrentFocus()["jsview"]; 58 | if (tnsButton && tnsButton !== this.highlightedElement) { 59 | tnsButton.addPseudoClass("focused"); 60 | if (this.highlightedElement) { 61 | this.highlightedElement.deletePseudoClass("focused"); 62 | } 63 | this.highlightedElement = tnsButton; 64 | } 65 | return super.dispatchKeyEvent(event); 66 | } 67 | 68 | public onBackPressed(): void { 69 | this._callbacks.onBackPressed(this, super.onBackPressed); 70 | } 71 | 72 | public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { 73 | this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined); 74 | } 75 | 76 | protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { 77 | this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/main-page-tv.css: -------------------------------------------------------------------------------- 1 | Label { 2 | color: #fff; 3 | } 4 | 5 | .nav { 6 | background-color: #87cefa; 7 | } 8 | 9 | .nav StackLayout { 10 | padding: 20 30; 11 | } 12 | 13 | .nav Label { 14 | font-weight: bold; 15 | font-size: 22; 16 | padding: 8 0; 17 | } 18 | 19 | .content { 20 | padding: 20 30; 21 | background-color: #f0f8ff; 22 | } 23 | 24 | .content Label { 25 | font-weight: bold; 26 | font-size: 22; 27 | color: #6494AA; 28 | } 29 | 30 | .content Image { 31 | margin: 20; 32 | border-radius: 10; 33 | } 34 | 35 | .nav button { 36 | background-color: #87cefa; 37 | border-color: #fff; 38 | border-width: 1; 39 | padding: 10; 40 | margin: 14 0; 41 | font-size: 17; 42 | border-radius: 5; 43 | } 44 | 45 | .nav button:focused { 46 | background-color: #65aafa; 47 | } -------------------------------------------------------------------------------- /app/main-page-tv.ts: -------------------------------------------------------------------------------- 1 | import * as observable from "tns-core-modules/data/observable"; 2 | import * as pages from "tns-core-modules/ui/page"; 3 | import { HelloWorldModel } from "./main-view-model"; 4 | import * as utils from "tns-core-modules/utils/utils"; 5 | import { ViewBase } from "tns-core-modules/ui/core/view-base"; 6 | import { Button } from "tns-core-modules/ui/button"; 7 | 8 | declare const android: any; 9 | 10 | const resourcename = "navbutton"; 11 | const res = utils.ad.getApplicationContext().getResources(); 12 | const identifier = res.getIdentifier(resourcename, "drawable", utils.ad.getApplication().getPackageName()); 13 | 14 | // Event handler for Page 'loaded' event attached in main-page.xml 15 | export function pageLoaded(args: observable.EventData) { 16 | // Get the event sender 17 | const page = args.object; 18 | page.actionBarHidden = true; 19 | page.bindingContext = new HelloWorldModel(); 20 | } 21 | 22 | export function elementLoaded(args: observable.EventData): void { 23 | const view = args.object; 24 | 25 | // There are 2 ways to make the TV controls highlight the currently focused element: 26 | 27 | // 1) use a resource that speficies a 'focused' state (uncomment the line below): 28 | // view.android.setBackgroundResource(identifier); 29 | 30 | // 2) don't use a resource, but set a backreference so 'dispatchKeyEvent' in app.ts can swap CSS classes 31 | view.android["jsview"] = args.object; 32 | } 33 | -------------------------------------------------------------------------------- /app/main-page-tv.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |