| /* |
| * Copyright 2015 Google Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.xyztouristattractions.ui; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.location.Location; |
| import android.os.Bundle; |
| import android.text.TextUtils; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| |
| import androidx.fragment.app.Fragment; |
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; |
| import androidx.recyclerview.widget.RecyclerView; |
| |
| import static com.example.android.xyztouristattractions.provider.TouristAttractions.ATTRACTIONS; |
| |
| import com.bumptech.glide.Glide; |
| import com.bumptech.glide.load.engine.DiskCacheStrategy; |
| import com.example.android.xyztouristattractions.R; |
| import com.example.android.xyztouristattractions.common.Attraction; |
| import com.example.android.xyztouristattractions.common.Constants; |
| import com.example.android.xyztouristattractions.common.Utils; |
| import com.example.android.xyztouristattractions.provider.TouristAttractions; |
| import com.example.android.xyztouristattractions.service.UtilityService; |
| import com.google.android.gms.location.FusedLocationProviderApi; |
| import com.google.android.gms.maps.model.LatLng; |
| import com.google.maps.android.SphericalUtil; |
| |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| /** |
| * The main tourist attraction fragment which contains a list of attractions |
| * sorted by distance (contained inside |
| * {@link com.example.android.xyztouristattractions.ui.AttractionListActivity}). |
| */ |
| public class AttractionListFragment extends Fragment { |
| |
| private AttractionAdapter mAdapter; |
| private LatLng mLatestLocation; |
| private int mImageSize; |
| private boolean mItemClicked; |
| |
| public AttractionListFragment() {} |
| |
| @Override |
| public View onCreateView(LayoutInflater inflater, ViewGroup container, |
| Bundle savedInstanceState) { |
| // Load a larger size image to make the activity transition to the detail screen smooth |
| mImageSize = getResources().getDimensionPixelSize(R.dimen.image_size) |
| * Constants.IMAGE_ANIM_MULTIPLIER; |
| |
| mLatestLocation = Utils.getLocation(getActivity()); |
| List<Attraction> attractions = loadAttractionsFromLocation(mLatestLocation); |
| mAdapter = new AttractionAdapter(getActivity(), attractions); |
| |
| View view = inflater.inflate(R.layout.fragment_main, container, false); |
| AttractionsRecyclerView recyclerView = |
| (AttractionsRecyclerView) view.findViewById(android.R.id.list); |
| recyclerView.setEmptyView(view.findViewById(android.R.id.empty)); |
| recyclerView.setHasFixedSize(true); |
| recyclerView.setAdapter(mAdapter); |
| |
| return view; |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| mItemClicked = false; |
| LocalBroadcastManager.getInstance(getActivity()).registerReceiver( |
| mBroadcastReceiver, UtilityService.getLocationUpdatedIntentFilter()); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mBroadcastReceiver); |
| } |
| |
| private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| Location location = |
| intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED); |
| if (location != null) { |
| mLatestLocation = new LatLng(location.getLatitude(), location.getLongitude()); |
| mAdapter.mAttractionList = loadAttractionsFromLocation(mLatestLocation); |
| mAdapter.notifyDataSetChanged(); |
| } |
| } |
| }; |
| |
| private static List<Attraction> loadAttractionsFromLocation(final LatLng curLatLng) { |
| String closestCity = TouristAttractions.getClosestCity(curLatLng); |
| if (closestCity != null) { |
| List<Attraction> attractions = ATTRACTIONS.get(closestCity); |
| if (curLatLng != null) { |
| Collections.sort(attractions, |
| new Comparator<Attraction>() { |
| @Override |
| public int compare(Attraction lhs, Attraction rhs) { |
| double lhsDistance = SphericalUtil.computeDistanceBetween( |
| lhs.location, curLatLng); |
| double rhsDistance = SphericalUtil.computeDistanceBetween( |
| rhs.location, curLatLng); |
| return (int) (lhsDistance - rhsDistance); |
| } |
| } |
| ); |
| } |
| return attractions; |
| } |
| return null; |
| } |
| |
| private class AttractionAdapter extends RecyclerView.Adapter<ViewHolder> |
| implements ItemClickListener { |
| |
| public List<Attraction> mAttractionList; |
| private Context mContext; |
| |
| public AttractionAdapter(Context context, List<Attraction> attractions) { |
| super(); |
| mContext = context; |
| mAttractionList = attractions; |
| } |
| |
| @Override |
| public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { |
| LayoutInflater inflater = LayoutInflater.from(mContext); |
| View view = inflater.inflate(R.layout.list_row, parent, false); |
| return new ViewHolder(view, this); |
| } |
| |
| @Override |
| public void onBindViewHolder(ViewHolder holder, int position) { |
| Attraction attraction = mAttractionList.get(position); |
| |
| holder.mTitleTextView.setText(attraction.name); |
| holder.mDescriptionTextView.setText(attraction.description); |
| Glide.with(mContext) |
| .load(attraction.imageUrl) |
| .diskCacheStrategy(DiskCacheStrategy.SOURCE) |
| .placeholder(R.drawable.empty_photo) |
| .override(mImageSize, mImageSize) |
| .into(holder.mImageView); |
| |
| String distance = |
| Utils.formatDistanceBetween(mLatestLocation, attraction.location); |
| if (TextUtils.isEmpty(distance)) { |
| holder.mOverlayTextView.setVisibility(View.GONE); |
| } else { |
| holder.mOverlayTextView.setVisibility(View.VISIBLE); |
| holder.mOverlayTextView.setText(distance); |
| } |
| } |
| |
| @Override |
| public long getItemId(int position) { |
| return position; |
| } |
| |
| @Override |
| public int getItemCount() { |
| return mAttractionList == null ? 0 : mAttractionList.size(); |
| } |
| |
| @Override |
| public void onItemClick(View view, int position) { |
| if (!mItemClicked) { |
| mItemClicked = true; |
| View heroView = view.findViewById(android.R.id.icon); |
| DetailActivity.launch( |
| getActivity(), mAdapter.mAttractionList.get(position).name, heroView); |
| } |
| } |
| } |
| |
| private static class ViewHolder extends RecyclerView.ViewHolder |
| implements View.OnClickListener { |
| |
| TextView mTitleTextView; |
| TextView mDescriptionTextView; |
| TextView mOverlayTextView; |
| ImageView mImageView; |
| ItemClickListener mItemClickListener; |
| |
| public ViewHolder(View view, ItemClickListener itemClickListener) { |
| super(view); |
| mTitleTextView = (TextView) view.findViewById(android.R.id.text1); |
| mDescriptionTextView = (TextView) view.findViewById(android.R.id.text2); |
| mOverlayTextView = (TextView) view.findViewById(R.id.overlaytext); |
| mImageView = (ImageView) view.findViewById(android.R.id.icon); |
| mItemClickListener = itemClickListener; |
| view.setOnClickListener(this); |
| } |
| |
| @Override |
| public void onClick(View v) { |
| mItemClickListener.onItemClick(v, getAdapterPosition()); |
| } |
| } |
| |
| interface ItemClickListener { |
| void onItemClick(View view, int position); |
| } |
| } |