1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.pump.activity; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.view.LayoutInflater; 24 import android.view.Menu; 25 import android.view.View; 26 import android.view.ViewGroup; 27 import android.widget.AdapterView; 28 import android.widget.BaseAdapter; 29 import android.widget.ImageView; 30 import android.widget.Spinner; 31 import android.widget.TextView; 32 33 import androidx.annotation.LayoutRes; 34 import androidx.annotation.NonNull; 35 import androidx.annotation.Nullable; 36 import androidx.annotation.UiThread; 37 import androidx.appcompat.app.ActionBar; 38 import androidx.appcompat.app.AppCompatActivity; 39 import androidx.recyclerview.widget.RecyclerView; 40 41 import com.android.pump.R; 42 import com.android.pump.db.Episode; 43 import com.android.pump.db.MediaDb; 44 import com.android.pump.db.Series; 45 import com.android.pump.util.Globals; 46 47 import java.util.List; 48 49 @UiThread 50 public class SeriesDetailsActivity extends AppCompatActivity implements MediaDb.UpdateCallback { 51 private MediaDb mMediaDb; 52 private Series mSeries; 53 start(@onNull Context context, @NonNull Series series)54 public static void start(@NonNull Context context, @NonNull Series series) { 55 Intent intent = new Intent(context, SeriesDetailsActivity.class); 56 // TODO(b/123704452) Pass URI instead 57 intent.putExtra("title", series.getTitle()); // TODO Add constant key 58 if (series.hasYear()) { 59 intent.putExtra("year", series.getYear()); // TODO Add constant key 60 } 61 context.startActivity(intent); 62 } 63 64 @Override onCreate(@ullable Bundle savedInstanceState)65 protected void onCreate(@Nullable Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 setContentView(R.layout.activity_series_details); 68 69 setSupportActionBar(findViewById(R.id.activity_series_details_toolbar)); 70 ActionBar actionBar = getSupportActionBar(); 71 if (actionBar != null) { 72 actionBar.setDisplayShowTitleEnabled(false); 73 actionBar.setDisplayShowHomeEnabled(true); 74 actionBar.setDisplayHomeAsUpEnabled(true); 75 } 76 77 mMediaDb = Globals.getMediaDb(this); 78 mMediaDb.addSeriesUpdateCallback(this); 79 80 handleIntent(); 81 } 82 83 @Override onNewIntent(@ullable Intent intent)84 protected void onNewIntent(@Nullable Intent intent) { 85 super.onNewIntent(intent); 86 setIntent(intent); 87 88 handleIntent(); 89 } 90 91 @Override onDestroy()92 protected void onDestroy() { 93 mMediaDb.removeSeriesUpdateCallback(this); 94 95 super.onDestroy(); 96 } 97 98 @Override onCreateOptionsMenu(@onNull Menu menu)99 public boolean onCreateOptionsMenu(@NonNull Menu menu) { 100 getMenuInflater().inflate(R.menu.activity_pump, menu); // TODO activity_series_details ? 101 return true; 102 } 103 104 @Override onSupportNavigateUp()105 public boolean onSupportNavigateUp() { 106 // TODO It should not be necessary to override this method 107 onBackPressed(); 108 return true; 109 } 110 111 @Override onItemsInserted(int index, int count)112 public void onItemsInserted(int index, int count) { } 113 114 @Override onItemsUpdated(int index, int count)115 public void onItemsUpdated(int index, int count) { 116 for (int i = index; i < index + count; ++i) { 117 Series series = mMediaDb.getSeries().get(i); 118 if (series.equals(mSeries)) { 119 updateViews(); 120 break; 121 } 122 } 123 } 124 125 @Override onItemsRemoved(int index, int count)126 public void onItemsRemoved(int index, int count) { } 127 handleIntent()128 private void handleIntent() { 129 Intent intent = getIntent(); 130 Bundle extras = intent != null ? intent.getExtras() : null; 131 if (extras != null) { 132 String title = extras.getString("title"); 133 int year = extras.getInt("year", Integer.MIN_VALUE); 134 135 MediaDb mediaDb = Globals.getMediaDb(this); 136 if (year > 0) { 137 mSeries = mediaDb.getSeriesById(title, year); 138 } else { 139 mSeries = mediaDb.getSeriesById(title); 140 } 141 } else { 142 mSeries = null; 143 // TODO This shouldn't happen -- throw exception? 144 } 145 146 mMediaDb.loadData(mSeries); 147 updateViews(); 148 } 149 updateViews()150 private void updateViews() { 151 // TODO ImageView imageView = findViewById(R.id.activity_series_details_image); 152 ImageView posterView = findViewById(R.id.activity_series_details_poster); 153 TextView titleView = findViewById(R.id.activity_series_details_title); 154 TextView attributesView = findViewById(R.id.activity_series_details_attributes); 155 TextView synopsisView = findViewById(R.id.activity_series_details_description); 156 157 // TODO imageView.setImageURI(mSeries.get???()); 158 posterView.setImageURI(mSeries.getPosterUri()); 159 titleView.setText(mSeries.getTitle()); 160 attributesView.setText("American Drama Series"); // TODO(b/123707108) Implement 161 synopsisView.setText(mSeries.getDescription()); 162 163 Spinner spinner = findViewById(R.id.activity_series_details_spinner); 164 spinner.setAdapter(new BaseAdapter() { 165 @Override 166 public boolean hasStableIds() { 167 return true; 168 } 169 170 @Override 171 public int getCount() { 172 return mSeries.getSeasons().size(); 173 } 174 175 @Override 176 public @NonNull Integer getItem(int position) { 177 return mSeries.getSeasons().get(position).get(0).getSeason(); 178 } 179 180 @Override 181 public long getItemId(int position) { 182 return getItem(position); 183 } 184 185 @Override 186 public View getView(int position, @Nullable View convertView, 187 @NonNull ViewGroup parent) { 188 return getView(android.R.layout.simple_spinner_item, position, convertView, parent); 189 } 190 191 @Override 192 public View getDropDownView(int position, @Nullable View convertView, 193 @NonNull ViewGroup parent) { 194 return getView(R.layout.support_simple_spinner_dropdown_item, 195 position, convertView, parent); 196 } 197 198 private View getView(@LayoutRes int resource, int position, @Nullable View convertView, 199 @NonNull ViewGroup parent) { 200 View view = convertView; 201 if (view == null) { 202 view = getInflater().inflate(resource, parent, false); 203 } 204 205 TextView textView = view.findViewById(android.R.id.text1); 206 // TODO(b/123037263) I18n -- Move to resource 207 textView.setText("Season " + getItem(position)); 208 return view; 209 } 210 211 private @NonNull LayoutInflater getInflater() { 212 return LayoutInflater.from(SeriesDetailsActivity.this); 213 } 214 }); 215 216 RecyclerView recyclerView = findViewById(R.id.activity_series_details_recycler_view); 217 recyclerView.setHasFixedSize(true); 218 recyclerView.setAdapter(new SeriesAdapter(mMediaDb, mSeries)); 219 spinner.setOnItemSelectedListener((SeriesAdapter) recyclerView.getAdapter()); 220 221 // TODO(b/123707260) Enable view caching 222 //recyclerView.setItemViewCacheSize(0); 223 //recyclerView.setRecycledViewPool(Globals.getRecycledViewPool(requireContext())); 224 } 225 226 private static class SeriesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 227 implements AdapterView.OnItemSelectedListener{ 228 private final MediaDb mMediaDb; 229 private final Series mSeries; 230 private int mSeasonPosition; 231 SeriesAdapter(@onNull MediaDb mediaDb, @NonNull Series series)232 private SeriesAdapter(@NonNull MediaDb mediaDb, @NonNull Series series) { 233 setHasStableIds(true); 234 mMediaDb = mediaDb; 235 mSeries = series; 236 } 237 238 @Override onCreateViewHolder( @onNull ViewGroup parent, int viewType)239 public @NonNull RecyclerView.ViewHolder onCreateViewHolder( 240 @NonNull ViewGroup parent, int viewType) { 241 return new EpisodeViewHolder(LayoutInflater.from(parent.getContext()) 242 .inflate(viewType, parent, false)); 243 } 244 245 @Override onBindViewHolder(@onNull RecyclerView.ViewHolder holder, int position)246 public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 247 Episode episode = getSeason().get(position); 248 mMediaDb.loadData(episode); // TODO Where should we call this? In bind()? 249 ((EpisodeViewHolder) holder).bind(episode); 250 } 251 252 @Override getItemCount()253 public int getItemCount() { 254 return getSeason().size(); 255 } 256 257 @Override getItemId(int position)258 public long getItemId(int position) { 259 return getSeason().get(position).getId(); 260 } 261 262 @Override getItemViewType(int position)263 public int getItemViewType(int position) { 264 return R.layout.episode; 265 } 266 267 @Override onItemSelected(@onNull AdapterView<?> parent, @NonNull View view, int position, long id)268 public void onItemSelected(@NonNull AdapterView<?> parent, @NonNull View view, 269 int position, long id) { 270 mSeasonPosition = position; 271 notifyDataSetChanged(); 272 } 273 274 @Override onNothingSelected(@onNull AdapterView<?> parent)275 public void onNothingSelected(@NonNull AdapterView<?> parent) { } 276 getSeason()277 private @NonNull List<Episode> getSeason() { 278 return mSeries.getSeasons().get(mSeasonPosition); 279 } 280 } 281 282 private static class EpisodeViewHolder extends RecyclerView.ViewHolder { EpisodeViewHolder(@onNull View itemView)283 private EpisodeViewHolder(@NonNull View itemView) { 284 super(itemView); 285 } 286 bind(@onNull Episode episode)287 private void bind(@NonNull Episode episode) { 288 ImageView imageView = itemView.findViewById(R.id.episode_image); 289 TextView textView = itemView.findViewById(R.id.episode_text); 290 291 Uri posterUri = episode.getPosterUri(); 292 if (posterUri == null) { 293 posterUri = episode.getThumbnailUri(); 294 } 295 imageView.setImageURI(posterUri); 296 // TODO(b/123037263) I18n -- Move to resource 297 textView.setText("Episode " + episode.getEpisode()); 298 299 itemView.setOnClickListener((view) -> 300 VideoPlayerActivity.start(view.getContext(), episode)); 301 } 302 } 303 } 304