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