Java tutorial
/* * Transportr * * Copyright (c) 2013 - 2018 Torsten Grote * * This program is Free Software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.grobox.transportr.locations; import android.arch.lifecycle.ViewModelProvider; import android.arch.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.ContextCompat; import android.support.v4.content.Loader; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import java.util.ArrayList; import java.util.Date; import java.util.SortedSet; import java.util.TreeSet; import javax.annotation.ParametersAreNonnullByDefault; import javax.inject.Inject; import de.grobox.transportr.R; import de.grobox.transportr.TransportrFragment; import de.grobox.transportr.departures.DeparturesActivity; import de.grobox.transportr.departures.DeparturesLoader; import de.grobox.transportr.locations.ReverseGeocoder.ReverseGeocoderCallback; import de.grobox.transportr.map.MapViewModel; import de.grobox.transportr.utils.IntentUtils; import de.grobox.transportr.utils.TransportrUtils; import de.schildbach.pte.dto.Departure; import de.schildbach.pte.dto.Line; import de.schildbach.pte.dto.LineDestination; import de.schildbach.pte.dto.QueryDeparturesResult; import de.schildbach.pte.dto.StationDepartures; import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static com.google.common.base.Strings.isNullOrEmpty; import static de.grobox.transportr.departures.DeparturesActivity.MAX_DEPARTURES; import static de.grobox.transportr.departures.DeparturesLoader.getBundle; import static de.grobox.transportr.utils.Constants.LOADER_DEPARTURES; import static de.grobox.transportr.utils.Constants.WRAP_LOCATION; import static de.grobox.transportr.utils.IntentUtils.startGeoIntent; import static de.schildbach.pte.dto.LocationType.COORD; import static de.schildbach.pte.dto.QueryDeparturesResult.Status.OK; @ParametersAreNonnullByDefault public class LocationFragment extends TransportrFragment implements LoaderCallbacks<QueryDeparturesResult>, ReverseGeocoderCallback, OnGlobalLayoutListener { public static final String TAG = LocationFragment.class.getName(); @Inject ViewModelProvider.Factory viewModelFactory; private MapViewModel viewModel; private WrapLocation location; private final LineAdapter adapter = new LineAdapter(); private ImageView locationIcon; private TextView locationName; private TextView locationInfo; private RecyclerView linesLayout; private Button nearbyStationsButton; private ProgressBar nearbyStationsProgress; public static LocationFragment newInstance(WrapLocation location) { LocationFragment f = new LocationFragment(); Bundle args = new Bundle(); args.putSerializable(WRAP_LOCATION, location); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = getArguments(); if (args == null) throw new IllegalStateException(); location = (WrapLocation) args.getSerializable(WRAP_LOCATION); if (location == null) throw new IllegalArgumentException("No location"); View v = inflater.inflate(R.layout.fragment_location, container, false); getComponent().inject(this); if (getActivity() == null) throw new IllegalStateException(); viewModel = ViewModelProviders.of(getActivity(), viewModelFactory).get(MapViewModel.class); viewModel.nearbyStationsFound().observe(this, found -> onNearbyStationsLoaded()); // Location locationIcon = v.findViewById(R.id.locationIcon); locationName = v.findViewById(R.id.locationName); locationIcon.setOnClickListener(view -> onLocationClicked()); locationName.setOnClickListener(view -> onLocationClicked()); // Lines linesLayout = v.findViewById(R.id.linesLayout); linesLayout.setVisibility(GONE); linesLayout.setAdapter(adapter); linesLayout.setLayoutManager(new LinearLayoutManager(getContext(), HORIZONTAL, false)); linesLayout.setOnClickListener(view -> onLocationClicked()); // Location Info locationInfo = v.findViewById(R.id.locationInfo); showLocation(); if (location.getLocation().type == COORD) { ReverseGeocoder geocoder = new ReverseGeocoder(getActivity(), this); geocoder.findLocation(location.getLocation()); } // Departures Button departuresButton = v.findViewById(R.id.departuresButton); if (location.hasId()) { departuresButton.setOnClickListener(view -> { Intent intent = new Intent(getContext(), DeparturesActivity.class); intent.putExtra(WRAP_LOCATION, location); startActivity(intent); }); } else { departuresButton.setVisibility(GONE); } // Nearby Stations nearbyStationsButton = v.findViewById(R.id.nearbyStationsButton); nearbyStationsProgress = v.findViewById(R.id.nearbyStationsProgress); nearbyStationsButton.setOnClickListener(view -> { nearbyStationsButton.setVisibility(INVISIBLE); nearbyStationsProgress.setVisibility(VISIBLE); IntentUtils.findNearbyStations(getContext(), location); }); // Share Location Button shareButton = v.findViewById(R.id.shareButton); shareButton.setOnClickListener(view -> startGeoIntent(getActivity(), location)); // Overflow Button ImageButton overflowButton = v.findViewById(R.id.overflowButton); overflowButton.setOnClickListener(view -> new LocationPopupMenu(getContext(), view, location).show()); v.getViewTreeObserver().addOnGlobalLayoutListener(this); return v; } @Override public void onGlobalLayout() { // set peek distance to show view header if (getActivity() == null) return; if (linesLayout.getBottom() > 0) { viewModel.setPeekHeight( linesLayout.getBottom() + getResources().getDimensionPixelSize(R.dimen.locationPeekPadding)); } else if (locationInfo.getBottom() > 0) { viewModel.setPeekHeight( locationInfo.getBottom() + getResources().getDimensionPixelSize(R.dimen.locationPeekPadding)); } } private void showLocation() { locationName.setText(location.getName()); locationIcon.setImageDrawable(ContextCompat.getDrawable(getContext(), location.getDrawable())); StringBuilder locationInfoStr = new StringBuilder(); if (!isNullOrEmpty(location.getLocation().place)) { locationInfoStr.append(location.getLocation().place); } if (location.getLocation().hasLocation()) { if (locationInfoStr.length() > 0) locationInfoStr.append(", "); locationInfoStr.append(TransportrUtils.getCoordName(location.getLocation())); } locationInfo.setText(locationInfoStr); } private void onLocationClicked() { viewModel.selectedLocationClicked(location.getLatLng()); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (location.hasId()) { Bundle args = getBundle(location.getId(), new Date(), MAX_DEPARTURES); getLoaderManager().initLoader(LOADER_DEPARTURES, args, this).forceLoad(); } } @NonNull @Override public DeparturesLoader onCreateLoader(int id, @Nullable Bundle args) { return new DeparturesLoader(getContext(), viewModel.getTransportNetwork().getValue(), args); } @Override public void onLoadFinished(Loader<QueryDeparturesResult> loader, QueryDeparturesResult data) { if (data != null && data.status == OK) { SortedSet<Line> lines = new TreeSet<>(); for (StationDepartures s : data.stationDepartures) { if (s.lines != null) { for (LineDestination d : s.lines) lines.add(d.line); } for (Departure d : s.departures) lines.add(d.line); } adapter.swapLines(new ArrayList<>(lines)); linesLayout.setAlpha(0f); linesLayout.setVisibility(VISIBLE); linesLayout.animate().setDuration(750).alpha(1f).start(); } } @Override public void onLoaderReset(Loader<QueryDeparturesResult> loader) { } @Override @WorkerThread public void onLocationRetrieved(@NonNull final WrapLocation location) { if (getActivity() == null) return; runOnUiThread(() -> { LocationFragment.this.location = location; showLocation(); }); } private void onNearbyStationsLoaded() { nearbyStationsButton.setVisibility(VISIBLE); nearbyStationsButton.setEnabled(false); nearbyStationsProgress.setVisibility(INVISIBLE); } public WrapLocation getLocation() { return location; } }