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.fragment;
18 
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.view.LayoutInflater;
22 import android.view.View;
23 import android.view.ViewGroup;
24 import android.widget.ImageView;
25 import android.widget.TextView;
26 
27 import androidx.annotation.NonNull;
28 import androidx.annotation.Nullable;
29 import androidx.annotation.UiThread;
30 import androidx.fragment.app.Fragment;
31 import androidx.recyclerview.widget.RecyclerView;
32 
33 import com.android.pump.R;
34 import com.android.pump.activity.AudioPlayerActivity;
35 import com.android.pump.db.Album;
36 import com.android.pump.db.Artist;
37 import com.android.pump.db.Audio;
38 import com.android.pump.db.MediaDb;
39 import com.android.pump.util.Globals;
40 
41 import java.util.List;
42 
43 @UiThread
44 public class AudioFragment extends Fragment {
45     private RecyclerView mRecyclerView;
46 
newInstance()47     public static @NonNull Fragment newInstance() {
48         return new AudioFragment();
49     }
50 
51     @Override
onCreateView(@onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)52     public @NonNull View onCreateView(@NonNull LayoutInflater inflater,
53             @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
54         View view = inflater.inflate(R.layout.fragment_audio, container, false);
55         mRecyclerView = view.findViewById(R.id.fragment_audio_recycler_view);
56         mRecyclerView.setHasFixedSize(true);
57         mRecyclerView.setAdapter(new AudioAdapter(requireContext()));
58 
59         // TODO(b/123707260) Enable view caching
60         //mRecyclerView.setItemViewCacheSize(0);
61         //mRecyclerView.setRecycledViewPool(Globals.getRecycledViewPool(requireContext()));
62         return view;
63     }
64 
65     private static class AudioAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
66             implements MediaDb.UpdateCallback {
67         private final MediaDb mMediaDb;
68         private final List<Audio> mAudios; // TODO(b/123710968) Use android.support.v7.util.SortedList/android.support.v7.widget.util.SortedListAdapterCallback instead
69 
AudioAdapter(@onNull Context context)70         private AudioAdapter(@NonNull Context context) {
71             setHasStableIds(true);
72             mMediaDb = Globals.getMediaDb(context);
73             mAudios = mMediaDb.getAudios();
74         }
75 
onAttachedToRecyclerView(@onNull RecyclerView recyclerView)76         public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
77             mMediaDb.addAudioUpdateCallback(this);
78         }
79 
onDetachedFromRecyclerView(@onNull RecyclerView recyclerView)80         public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
81             mMediaDb.removeAudioUpdateCallback(this);
82         }
83 
84         @Override
onCreateViewHolder( @onNull ViewGroup parent, int viewType)85         public @NonNull RecyclerView.ViewHolder onCreateViewHolder(
86                 @NonNull ViewGroup parent, int viewType) {
87             if (viewType == R.layout.header) {
88                 return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext())
89                         .inflate(viewType, parent, false)) { };
90             } else {
91                 return new AudioViewHolder(LayoutInflater.from(parent.getContext())
92                         .inflate(viewType, parent, false));
93             }
94         }
95 
96         @Override
onBindViewHolder(@onNull RecyclerView.ViewHolder holder, int position)97         public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
98             if (position == 0) {
99                 // TODO Handle header view
100             } else {
101                 Audio audio = mAudios.get(position - 1);
102                 mMediaDb.loadData(audio); // TODO Where should we call this? In bind()?
103                 ((AudioViewHolder) holder).bind(audio);
104             }
105         }
106 
107         @Override
getItemCount()108         public int getItemCount() {
109             return mAudios.size() + 1;
110         }
111 
112         @Override
getItemId(int position)113         public long getItemId(int position) {
114             return position == 0 ? -1 : mAudios.get(position - 1).getId();
115         }
116 
117         @Override
getItemViewType(int position)118         public int getItemViewType(int position) {
119             return position == 0 ? R.layout.header : R.layout.audio;
120         }
121 
122         @Override
onItemsInserted(int index, int count)123         public void onItemsInserted(int index, int count) {
124             notifyItemRangeInserted(index + 1, count);
125         }
126 
127         @Override
onItemsUpdated(int index, int count)128         public void onItemsUpdated(int index, int count) {
129             notifyItemRangeChanged(index + 1, count);
130         }
131 
132         @Override
onItemsRemoved(int index, int count)133         public void onItemsRemoved(int index, int count) {
134             notifyItemRangeRemoved(index + 1, count);
135         }
136     }
137 
138     private static class AudioViewHolder extends RecyclerView.ViewHolder {
AudioViewHolder(@onNull View itemView)139         private AudioViewHolder(@NonNull View itemView) {
140             super(itemView);
141         }
142 
bind(@onNull Audio audio)143         private void bind(@NonNull Audio audio) {
144             ImageView imageView = itemView.findViewById(R.id.audio_image);
145             TextView titleView = itemView.findViewById(R.id.audio_title);
146             TextView artistView = itemView.findViewById(R.id.audio_artist);
147 
148             Album album = audio.getAlbum();
149             imageView.setImageURI(album == null ? null : album.getAlbumArtUri());
150             titleView.setText(audio.getTitle());
151             Artist artist = audio.getArtist();
152             artistView.setText(artist == null ? null : artist.getName());
153 
154             itemView.setOnClickListener((view) ->
155                     AudioPlayerActivity.start(view.getContext(), audio));
156         }
157     }
158 }
159