1 /* 2 * Copyright 2015 Google Inc. All rights reserved. 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.example.android.xyztouristattractions.ui; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.location.Location; 23 import android.os.Bundle; 24 import android.support.v4.app.Fragment; 25 import android.support.v4.content.LocalBroadcastManager; 26 import android.support.v7.widget.RecyclerView; 27 import android.text.TextUtils; 28 import android.view.LayoutInflater; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.ImageView; 32 import android.widget.TextView; 33 34 import com.bumptech.glide.Glide; 35 import com.bumptech.glide.load.engine.DiskCacheStrategy; 36 import com.example.android.xyztouristattractions.R; 37 import com.example.android.xyztouristattractions.common.Attraction; 38 import com.example.android.xyztouristattractions.common.Constants; 39 import com.example.android.xyztouristattractions.common.Utils; 40 import com.example.android.xyztouristattractions.provider.TouristAttractions; 41 import com.example.android.xyztouristattractions.service.UtilityService; 42 import com.google.android.gms.location.FusedLocationProviderApi; 43 import com.google.android.gms.maps.model.LatLng; 44 import com.google.maps.android.SphericalUtil; 45 46 import java.util.Collections; 47 import java.util.Comparator; 48 import java.util.List; 49 50 import static com.example.android.xyztouristattractions.provider.TouristAttractions.ATTRACTIONS; 51 52 /** 53 * The main tourist attraction fragment which contains a list of attractions 54 * sorted by distance (contained inside 55 * {@link com.example.android.xyztouristattractions.ui.AttractionListActivity}). 56 */ 57 public class AttractionListFragment extends Fragment { 58 59 private AttractionAdapter mAdapter; 60 private LatLng mLatestLocation; 61 private int mImageSize; 62 private boolean mItemClicked; 63 AttractionListFragment()64 public AttractionListFragment() {} 65 66 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)67 public View onCreateView(LayoutInflater inflater, ViewGroup container, 68 Bundle savedInstanceState) { 69 // Load a larger size image to make the activity transition to the detail screen smooth 70 mImageSize = getResources().getDimensionPixelSize(R.dimen.image_size) 71 * Constants.IMAGE_ANIM_MULTIPLIER; 72 73 mLatestLocation = Utils.getLocation(getActivity()); 74 List<Attraction> attractions = loadAttractionsFromLocation(mLatestLocation); 75 mAdapter = new AttractionAdapter(getActivity(), attractions); 76 77 View view = inflater.inflate(R.layout.fragment_main, container, false); 78 AttractionsRecyclerView recyclerView = 79 (AttractionsRecyclerView) view.findViewById(android.R.id.list); 80 recyclerView.setEmptyView(view.findViewById(android.R.id.empty)); 81 recyclerView.setHasFixedSize(true); 82 recyclerView.setAdapter(mAdapter); 83 84 return view; 85 } 86 87 @Override onResume()88 public void onResume() { 89 super.onResume(); 90 mItemClicked = false; 91 LocalBroadcastManager.getInstance(getActivity()).registerReceiver( 92 mBroadcastReceiver, UtilityService.getLocationUpdatedIntentFilter()); 93 } 94 95 @Override onPause()96 public void onPause() { 97 super.onPause(); 98 LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mBroadcastReceiver); 99 } 100 101 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 102 @Override 103 public void onReceive(Context context, Intent intent) { 104 Location location = 105 intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED); 106 if (location != null) { 107 mLatestLocation = new LatLng(location.getLatitude(), location.getLongitude()); 108 mAdapter.mAttractionList = loadAttractionsFromLocation(mLatestLocation); 109 mAdapter.notifyDataSetChanged(); 110 } 111 } 112 }; 113 loadAttractionsFromLocation(final LatLng curLatLng)114 private static List<Attraction> loadAttractionsFromLocation(final LatLng curLatLng) { 115 String closestCity = TouristAttractions.getClosestCity(curLatLng); 116 if (closestCity != null) { 117 List<Attraction> attractions = ATTRACTIONS.get(closestCity); 118 if (curLatLng != null) { 119 Collections.sort(attractions, 120 new Comparator<Attraction>() { 121 @Override 122 public int compare(Attraction lhs, Attraction rhs) { 123 double lhsDistance = SphericalUtil.computeDistanceBetween( 124 lhs.location, curLatLng); 125 double rhsDistance = SphericalUtil.computeDistanceBetween( 126 rhs.location, curLatLng); 127 return (int) (lhsDistance - rhsDistance); 128 } 129 } 130 ); 131 } 132 return attractions; 133 } 134 return null; 135 } 136 137 private class AttractionAdapter extends RecyclerView.Adapter<ViewHolder> 138 implements ItemClickListener { 139 140 public List<Attraction> mAttractionList; 141 private Context mContext; 142 AttractionAdapter(Context context, List<Attraction> attractions)143 public AttractionAdapter(Context context, List<Attraction> attractions) { 144 super(); 145 mContext = context; 146 mAttractionList = attractions; 147 } 148 149 @Override onCreateViewHolder(ViewGroup parent, int viewType)150 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 151 LayoutInflater inflater = LayoutInflater.from(mContext); 152 View view = inflater.inflate(R.layout.list_row, parent, false); 153 return new ViewHolder(view, this); 154 } 155 156 @Override onBindViewHolder(ViewHolder holder, int position)157 public void onBindViewHolder(ViewHolder holder, int position) { 158 Attraction attraction = mAttractionList.get(position); 159 160 holder.mTitleTextView.setText(attraction.name); 161 holder.mDescriptionTextView.setText(attraction.description); 162 Glide.with(mContext) 163 .load(attraction.imageUrl) 164 .diskCacheStrategy(DiskCacheStrategy.SOURCE) 165 .placeholder(R.drawable.empty_photo) 166 .override(mImageSize, mImageSize) 167 .into(holder.mImageView); 168 169 String distance = 170 Utils.formatDistanceBetween(mLatestLocation, attraction.location); 171 if (TextUtils.isEmpty(distance)) { 172 holder.mOverlayTextView.setVisibility(View.GONE); 173 } else { 174 holder.mOverlayTextView.setVisibility(View.VISIBLE); 175 holder.mOverlayTextView.setText(distance); 176 } 177 } 178 179 @Override getItemId(int position)180 public long getItemId(int position) { 181 return position; 182 } 183 184 @Override getItemCount()185 public int getItemCount() { 186 return mAttractionList == null ? 0 : mAttractionList.size(); 187 } 188 189 @Override onItemClick(View view, int position)190 public void onItemClick(View view, int position) { 191 if (!mItemClicked) { 192 mItemClicked = true; 193 View heroView = view.findViewById(android.R.id.icon); 194 DetailActivity.launch( 195 getActivity(), mAdapter.mAttractionList.get(position).name, heroView); 196 } 197 } 198 } 199 200 private static class ViewHolder extends RecyclerView.ViewHolder 201 implements View.OnClickListener { 202 203 TextView mTitleTextView; 204 TextView mDescriptionTextView; 205 TextView mOverlayTextView; 206 ImageView mImageView; 207 ItemClickListener mItemClickListener; 208 ViewHolder(View view, ItemClickListener itemClickListener)209 public ViewHolder(View view, ItemClickListener itemClickListener) { 210 super(view); 211 mTitleTextView = (TextView) view.findViewById(android.R.id.text1); 212 mDescriptionTextView = (TextView) view.findViewById(android.R.id.text2); 213 mOverlayTextView = (TextView) view.findViewById(R.id.overlaytext); 214 mImageView = (ImageView) view.findViewById(android.R.id.icon); 215 mItemClickListener = itemClickListener; 216 view.setOnClickListener(this); 217 } 218 219 @Override onClick(View v)220 public void onClick(View v) { 221 mItemClickListener.onItemClick(v, getAdapterPosition()); 222 } 223 } 224 225 interface ItemClickListener { onItemClick(View view, int position)226 void onItemClick(View view, int position); 227 } 228 } 229