> { videos ->
74 | videos?.apply {
75 | viewModelAdapter?.videos = videos
76 | }
77 | })
78 | }
79 |
80 | /**
81 | * Called to have the fragment instantiate its user interface view.
82 | *
83 | * If you return a View from here, you will later be called in
84 | * {@link #onDestroyView} when the view is being released.
85 | *
86 | * @param inflater The LayoutInflater object that can be used to inflate
87 | * any views in the fragment,
88 | * @param container If non-null, this is the parent view that the fragment's
89 | * UI should be attached to. The fragment should not add the view itself,
90 | * but this can be used to generate the LayoutParams of the view.
91 | * @param savedInstanceState If non-null, this fragment is being re-constructed
92 | * from a previous saved state as given here.
93 | *
94 | * @return Return the View for the fragment's UI.
95 | */
96 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
97 | savedInstanceState: Bundle?): View? {
98 | val binding: FragmentDevByteBinding = DataBindingUtil.inflate(
99 | inflater,
100 | R.layout.fragment_dev_byte,
101 | container,
102 | false)
103 | // Set the lifecycleOwner so DataBinding can observe LiveData
104 | binding.setLifecycleOwner(viewLifecycleOwner)
105 |
106 | binding.viewModel = viewModel
107 |
108 | viewModelAdapter = DevByteAdapter(VideoClick {
109 | // When a video is clicked this block or lambda will be called by DevByteAdapter
110 |
111 | // context is not around, we can safely discard this click since the Fragment is no
112 | // longer on the screen
113 | val packageManager = context?.packageManager ?: return@VideoClick
114 |
115 | // Try to generate a direct intent to the YouTube app
116 | var intent = Intent(Intent.ACTION_VIEW, it.launchUri)
117 | if(intent.resolveActivity(packageManager) == null) {
118 | // YouTube app isn't found, use the web url
119 | intent = Intent(Intent.ACTION_VIEW, Uri.parse(it.url))
120 | }
121 |
122 | startActivity(intent)
123 | })
124 |
125 | binding.root.findViewById(R.id.recycler_view).apply {
126 | layoutManager = LinearLayoutManager(context)
127 | adapter = viewModelAdapter
128 | }
129 |
130 | return binding.root
131 | }
132 |
133 | /**
134 | * Helper method to generate YouTube app links
135 | */
136 | private val Video.launchUri: Uri
137 | get() {
138 | val httpUri = Uri.parse(url)
139 | return Uri.parse("vnd.youtube:" + httpUri.getQueryParameter("v"))
140 | }
141 | }
142 |
143 | /**
144 | * Click listener for Videos. By giving the block a name it helps a reader understand what it does.
145 | *
146 | */
147 | class VideoClick(val block: (Video) -> Unit) {
148 | /**
149 | * Called when a video is clicked
150 | *
151 | * @param video the video that was clicked
152 | */
153 | fun onClick(video: Video) = block(video)
154 | }
155 |
156 | /**
157 | * RecyclerView Adapter for setting up data binding on the items in the list.
158 | */
159 | class DevByteAdapter(val callback: VideoClick) : RecyclerView.Adapter() {
160 |
161 | /**
162 | * The videos that our Adapter will show
163 | */
164 | var videos: List