diff --git a/app/src/main/java/de/grobox/transportr/settings/SettingsManager.kt b/app/src/main/java/de/grobox/transportr/settings/SettingsManager.kt
index d3e35a10c..e930f08f0 100644
--- a/app/src/main/java/de/grobox/transportr/settings/SettingsManager.kt
+++ b/app/src/main/java/de/grobox/transportr/settings/SettingsManager.kt
@@ -96,11 +96,6 @@ class SettingsManager @Inject constructor(private val context: Context) {
settings.edit().putBoolean(TRIP_DETAIL_ONBOARDING, false).apply()
}
- fun showDirectionsOnboarding(): Boolean = settings.getBoolean(DIRECTIONS_ONBOARDING, true)
- fun directionsOnboardingShown() {
- settings.edit().putBoolean(DIRECTIONS_ONBOARDING, false).apply()
- }
-
fun getNetworkId(i: Int): NetworkId? {
var networkSettingsStr = NETWORK_ID_1
if (i == 2) networkSettingsStr = NETWORK_ID_2
diff --git a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.java b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.java
deleted file mode 100644
index 90fce7e56..000000000
--- a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * 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 .
- */
-
-package de.grobox.transportr.trips.search;
-
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.lifecycle.ViewModelProviders;
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.cardview.widget.CardView;
-import androidx.appcompat.widget.Toolbar;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.Calendar;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-import javax.inject.Inject;
-
-import de.grobox.transportr.R;
-import de.grobox.transportr.TransportrFragment;
-import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType;
-import de.grobox.transportr.locations.LocationGpsView;
-import de.grobox.transportr.locations.LocationView;
-import de.grobox.transportr.locations.WrapLocation;
-import de.grobox.transportr.networks.TransportNetwork;
-import de.grobox.transportr.settings.SettingsManager;
-import de.grobox.transportr.ui.TimeDateFragment;
-import de.grobox.transportr.utils.DateUtils;
-import de.grobox.transportr.utils.IconOnboardingBuilder;
-
-import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-import static android.view.animation.Animation.RELATIVE_TO_SELF;
-import static de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.FROM;
-import static de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.TO;
-import static de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.VIA;
-import static de.grobox.transportr.utils.Constants.DATE;
-import static de.grobox.transportr.utils.Constants.DEPARTURE;
-import static de.grobox.transportr.utils.Constants.EXPANDED;
-import static de.grobox.transportr.utils.DateUtils.getDate;
-import static de.grobox.transportr.utils.DateUtils.getTime;
-import static de.grobox.transportr.utils.DateUtils.isNow;
-import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
-import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FOCAL_PRESSED;
-
-@ParametersAreNonnullByDefault
-public class DirectionsFragment extends TransportrFragment {
-
- @Inject SettingsManager settingsManager;
- @Inject ViewModelProvider.Factory viewModelFactory;
-
- private Toolbar toolbar;
- private @Nullable Menu menu;
- private ImageView favIcon, timeIcon;
- private TextView date, time;
- private LocationGpsView from;
- private LocationView via, to;
- private CardView fromCard, viaCard, toCard;
-
- private DirectionsViewModel viewModel;
-
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_directions_form, container, false);
- getComponent().inject(this);
-
- setHasOptionsMenu(true);
- toolbar = v.findViewById(R.id.toolbar);
- favIcon = toolbar.findViewById(R.id.favIcon);
- timeIcon = toolbar.findViewById(R.id.timeIcon);
- date = toolbar.findViewById(R.id.date);
- time = toolbar.findViewById(R.id.time);
-
- fromCard = v.findViewById(R.id.fromCard);
- viaCard = v.findViewById(R.id.viaCard);
- toCard = v.findViewById(R.id.toCard);
- from = v.findViewById(R.id.fromLocation);
- via = v.findViewById(R.id.viaLocation);
- to = v.findViewById(R.id.toLocation);
-
- setUpToolbar(toolbar);
-
- viewModel = new ViewModelProvider(requireActivity(), viewModelFactory).get(DirectionsViewModel.class);
- TransportNetwork network = viewModel.getTransportNetwork().getValue();
- if (network == null) throw new IllegalStateException();
- from.setTransportNetwork(network);
- via.setTransportNetwork(network);
- to.setTransportNetwork(network);
-
- from.setType(FROM);
- via.setType(VIA);
- to.setType(TO);
-
- viewModel.getHome().observe(getViewLifecycleOwner(), homeLocation -> {
- from.setHomeLocation(homeLocation);
- via.setHomeLocation(homeLocation);
- to.setHomeLocation(homeLocation);
- });
- viewModel.getWork().observe(getViewLifecycleOwner(), workLocation -> {
- from.setWorkLocation(workLocation);
- via.setWorkLocation(workLocation);
- to.setWorkLocation(workLocation);
- });
- viewModel.getLocations().observe(getViewLifecycleOwner(), favoriteLocations -> {
- if (favoriteLocations == null) return;
- from.setFavoriteLocations(favoriteLocations);
- via.setFavoriteLocations(favoriteLocations);
- to.setFavoriteLocations(favoriteLocations);
- });
- viewModel.getFromLocation().observe(getViewLifecycleOwner(), location -> {
- from.setLocation(location);
- if (location != null) to.requestFocus();
- });
- viewModel.getViaLocation().observe(getViewLifecycleOwner(), location -> via.setLocation(location));
- viewModel.getToLocation().observe(getViewLifecycleOwner(), location -> to.setLocation(location));
- viewModel.getCalendar().observe(getViewLifecycleOwner(), this::onCalendarUpdated);
- viewModel.findGpsLocation.observe(getViewLifecycleOwner(), this::onFindGpsLocation);
- viewModel.isFavTrip().observe(getViewLifecycleOwner(), this::onFavStatusChanged);
-
- setupClickListeners();
-
- return v;
- }
-
- @Override
- @SuppressWarnings("ConstantConditions")
- public void onSaveInstanceState(@NonNull Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putSerializable(DATE, viewModel.getCalendar().getValue());
- outState.putBoolean(EXPANDED, viewModel.getIsExpanded().getValue());
- outState.putBoolean(DEPARTURE, viewModel.getIsDeparture().getValue());
- }
-
- @Override
- public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
- super.onViewStateRestored(savedInstanceState);
- if (savedInstanceState != null && viewModel.getTrips().getValue() == null) {
- viewModel.setIsExpanded(savedInstanceState.getBoolean(EXPANDED, false));
- viewModel.setIsDeparture(savedInstanceState.getBoolean(DEPARTURE, true));
- viewModel.setFromLocation(from.getLocation());
- viewModel.setViaLocation(via.getLocation());
- viewModel.setToLocation(to.getLocation());
- viewModel.onTimeAndDateSet((Calendar) savedInstanceState.getSerializable(DATE));
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.directions, menu);
- this.menu = menu;
- viewModel.getIsDeparture().observe(this, this::onIsDepartureChanged);
- viewModel.getIsExpanded().observe(this, this::onViaVisibleChanged);
- super.onCreateOptionsMenu(menu, inflater);
-
- // onboarding for overflow menu
- if (getActivity() != null && settingsManager.showDirectionsOnboarding()) {
- new IconOnboardingBuilder(getActivity())
- .setTarget(toolbar.getChildAt(toolbar.getChildCount() - 1))
- .setPrimaryText(R.string.onboarding_directions_title)
- .setSecondaryText(R.string.onboarding_directions_message)
- .setIcon(R.drawable.ic_more_vert)
- .setPromptStateChangeListener((prompt, state) -> {
- if (state == STATE_DISMISSED || state == STATE_FOCAL_PRESSED) {
- settingsManager.directionsOnboardingShown();
- }
- })
- .show();
- }
-
- Drawable drawable = menu.findItem(R.id.action_swap_locations).getIcon();
- if (drawable != null) {
- drawable.mutate();
- drawable.setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_swap_locations:
- swapLocations();
- return true;
- case R.id.action_departure:
- viewModel.setIsDeparture(true);
- return true;
- case R.id.action_arrival:
- viewModel.setIsDeparture(false);
- return true;
- case R.id.action_navigation_expand:
- viewModel.setIsExpanded(!item.isChecked());
- return true;
- case R.id.action_choose_products:
- new ProductDialogFragment().show(getActivity().getSupportFragmentManager(), ProductDialogFragment.TAG);
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupClickListeners() {
- favIcon.setVisibility(VISIBLE);
- favIcon.setOnClickListener(view -> viewModel.toggleFavTrip());
-
- OnClickListener onTimeClickListener = view -> {
- if (viewModel.getCalendar().getValue() == null) throw new IllegalStateException();
- TimeDateFragment fragment = TimeDateFragment.newInstance(viewModel.getCalendar().getValue());
- fragment.setTimeDateListener(viewModel);
- fragment.show(getActivity().getSupportFragmentManager(), TimeDateFragment.TAG);
- };
- OnLongClickListener onTimeLongClickListener = view -> {
- viewModel.resetCalender();
- return true;
- };
-
- timeIcon.setOnClickListener(onTimeClickListener);
- date.setOnClickListener(onTimeClickListener);
- time.setOnClickListener(onTimeClickListener);
-
- timeIcon.setOnLongClickListener(onTimeLongClickListener);
- date.setOnLongClickListener(onTimeLongClickListener);
- time.setOnLongClickListener(onTimeLongClickListener);
-
- from.setLocationViewListener(viewModel);
- via.setLocationViewListener(viewModel);
- to.setLocationViewListener(viewModel);
- }
-
- private void onCalendarUpdated(@Nullable Calendar calendar) {
- if (calendar == null) return;
- if (isNow(calendar)) {
- time.setText(R.string.now);
- date.setVisibility(GONE);
- } else if (DateUtils.isToday(calendar)) {
- time.setText(getTime(getContext(), calendar.getTime()));
- date.setVisibility(GONE);
- } else {
- time.setText(getTime(getContext(), calendar.getTime()));
- date.setText(getDate(getContext(), calendar.getTime()));
- date.setVisibility(VISIBLE);
- }
- }
-
- private void swapLocations() {
- float toToY = fromCard.getY() - toCard.getY();
- Animation slideUp = new TranslateAnimation(RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF,
- 0.0f, Animation.ABSOLUTE, toToY);
- slideUp.setDuration(400);
- slideUp.setFillAfter(true);
- slideUp.setFillEnabled(true);
-
- float fromToY = toCard.getY() - fromCard.getY();
- Animation slideDown = new TranslateAnimation(RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF,
- 0.0f, Animation.ABSOLUTE, fromToY);
- slideDown.setDuration(400);
- slideDown.setFillAfter(true);
- slideDown.setFillEnabled(true);
-
- fromCard.startAnimation(slideDown);
- toCard.startAnimation(slideUp);
-
- slideUp.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
-
- @Override
- public void onAnimationEnd(Animation animation) {
- // swap location objects
- WrapLocation tmp = to.getLocation();
- if (from.isSearching()) {
- viewModel.findGpsLocation.setValue(null);
- // TODO: GPS currently only supports from location, so don't swap it for now
- viewModel.setToLocation(null);
- } else {
- viewModel.setToLocation(from.getLocation());
- }
- viewModel.setFromLocation(tmp);
-
- fromCard.clearAnimation();
- toCard.clearAnimation();
-
- viewModel.search();
- }
- });
- }
-
- private void onIsDepartureChanged(boolean isDeparture) {
- if (menu == null) throw new IllegalStateException("Menu is null");
- if (isDeparture) {
- MenuItem departureItem = menu.findItem(R.id.action_departure);
- departureItem.setChecked(true);
- } else {
- MenuItem arrivalItem = menu.findItem(R.id.action_arrival);
- arrivalItem.setChecked(true);
- }
- }
-
- private void onViaVisibleChanged(boolean viaVisible) {
- if (menu == null) throw new IllegalStateException("Menu is null");
- MenuItem viaItem = menu.findItem(R.id.action_navigation_expand);
- viaItem.setChecked(viaVisible);
- viaCard.setVisibility(viaVisible ? VISIBLE : GONE);
- }
-
- private void onFindGpsLocation(@Nullable FavLocationType type) {
- if (type == null) {
- viewModel.locationLiveData.removeObservers(DirectionsFragment.this);
- from.clearSearching();
- return;
- }
- if (ContextCompat.checkSelfPermission(getContext(), ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) {
- return;
- }
- from.setSearching();
- to.requestFocus();
- viewModel.locationLiveData.observe(this, location -> {
- viewModel.setFromLocation(location);
- viewModel.search();
- viewModel.locationLiveData.removeObservers(DirectionsFragment.this);
- });
- }
-
- private void onFavStatusChanged(@Nullable Boolean isFav) {
- if (isFav == null) {
- favIcon.setVisibility(GONE);
- } else {
- favIcon.setVisibility(VISIBLE);
- if (isFav) {
- favIcon.setImageResource(R.drawable.ic_action_star);
- } else {
- favIcon.setImageResource(R.drawable.ic_action_star_empty);
- }
- }
- }
-
-}
diff --git a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt
new file mode 100644
index 000000000..a7b2ef78e
--- /dev/null
+++ b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt
@@ -0,0 +1,294 @@
+/*
+ * 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 .
+ */
+
+package de.grobox.transportr.trips.search
+
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Bundle
+import android.view.*
+import android.view.View.*
+import android.view.animation.Animation
+import android.view.animation.Animation.RELATIVE_TO_SELF
+import android.view.animation.TranslateAnimation
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.ViewModelProviders
+import de.grobox.transportr.R
+import de.grobox.transportr.TransportrFragment
+import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType
+import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.FROM
+import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.TO
+import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.VIA
+import de.grobox.transportr.settings.SettingsManager
+import de.grobox.transportr.ui.TimeDateFragment
+import de.grobox.transportr.utils.Constants.DATE
+import de.grobox.transportr.utils.Constants.DEPARTURE
+import de.grobox.transportr.utils.Constants.EXPANDED
+import de.grobox.transportr.utils.DateUtils
+import de.grobox.transportr.utils.DateUtils.*
+import kotlinx.android.synthetic.main.fragment_directions_form.*
+import java.util.*
+import javax.annotation.ParametersAreNonnullByDefault
+import javax.inject.Inject
+
+@ParametersAreNonnullByDefault
+class DirectionsFragment : TransportrFragment() {
+
+ @Inject
+ internal lateinit var settingsManager: SettingsManager
+ @Inject
+ internal lateinit var viewModelFactory: ViewModelProvider.Factory
+
+ private lateinit var viewModel: DirectionsViewModel
+ private var expandItem: MenuItem? = null
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ val v = inflater.inflate(R.layout.fragment_directions_form, container, false)
+ component.inject(this)
+
+ setHasOptionsMenu(true)
+
+ viewModel = ViewModelProviders.of(activity!!, viewModelFactory).get(DirectionsViewModel::class.java)
+
+ return v
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setUpToolbar(toolbar)
+
+ val network = viewModel.transportNetwork.value ?: throw IllegalStateException()
+ fromLocation.setTransportNetwork(network)
+ viaLocation.setTransportNetwork(network)
+ toLocation.setTransportNetwork(network)
+
+ fromLocation.type = FROM
+ viaLocation.type = VIA
+ toLocation.type = TO
+
+ fromLocation.setLocationViewListener(viewModel)
+ viaLocation.setLocationViewListener(viewModel)
+ toLocation.setLocationViewListener(viewModel)
+
+ viewModel.home.observe(this, Observer { homeLocation ->
+ fromLocation.setHomeLocation(homeLocation)
+ viaLocation.setHomeLocation(homeLocation)
+ toLocation.setHomeLocation(homeLocation)
+ })
+ viewModel.work.observe(this, Observer { workLocation ->
+ fromLocation.setWorkLocation(workLocation)
+ viaLocation.setWorkLocation(workLocation)
+ toLocation.setWorkLocation(workLocation)
+ })
+ viewModel.locations.observe(this, Observer { favoriteLocations ->
+ if (favoriteLocations == null) return@Observer
+ fromLocation.setFavoriteLocations(favoriteLocations)
+ viaLocation.setFavoriteLocations(favoriteLocations)
+ toLocation.setFavoriteLocations(favoriteLocations)
+ })
+ viewModel.fromLocation.observe(this, Observer { location ->
+ fromLocation.setLocation(location)
+ if (location != null) toLocation.requestFocus()
+ })
+ viewModel.viaLocation.observe(this, Observer { location -> viaLocation.setLocation(location) })
+ viewModel.toLocation.observe(this, Observer { location -> toLocation.setLocation(location) })
+ viewModel.isDeparture.observe(this, Observer { this.onIsDepartureChanged(it) })
+ viewModel.isExpanded.observe(this, Observer { this.onViaVisibleChanged(it) })
+ viewModel.calendar.observe(this, Observer { this.onCalendarUpdated(it) })
+ viewModel.findGpsLocation.observe(this, Observer { this.onFindGpsLocation(it) })
+ viewModel.isFavTrip.observe(this, Observer { this.onFavStatusChanged(it) })
+
+ favIcon.visibility = VISIBLE
+ favIcon.setOnClickListener { viewModel.toggleFavTrip() }
+
+ departureIcon.setOnClickListener { viewModel.toggleDeparture() }
+
+ val onTimeClickListener = OnClickListener {
+ if (viewModel.calendar.value == null) throw IllegalStateException()
+ val fragment = TimeDateFragment.newInstance(viewModel.calendar.value!!)
+ fragment.setTimeDateListener(viewModel)
+ fragment.show(activity!!.supportFragmentManager, TimeDateFragment.TAG)
+ }
+ val onTimeLongClickListener = OnLongClickListener {
+ viewModel.resetCalender()
+ true
+ }
+
+ timeIcon.setOnClickListener(onTimeClickListener)
+ date.setOnClickListener(onTimeClickListener)
+ time.setOnClickListener(onTimeClickListener)
+
+ timeIcon.setOnLongClickListener(onTimeLongClickListener)
+ date.setOnLongClickListener(onTimeLongClickListener)
+ time.setOnLongClickListener(onTimeLongClickListener)
+
+ productsIcon.setOnClickListener {
+ activity?.let { a ->
+ ProductDialogFragment().show(a.supportFragmentManager, ProductDialogFragment.TAG)
+ }
+ }
+ swapIcon.setOnClickListener { swapLocations() }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putSerializable(DATE, viewModel.calendar.value)
+ outState.putBoolean(EXPANDED, viewModel.isExpanded.value ?: false)
+ outState.putBoolean(DEPARTURE, viewModel.isDeparture.value ?: true)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ super.onViewStateRestored(savedInstanceState)
+ if (savedInstanceState != null && viewModel.trips.value == null) {
+ viewModel.setIsExpanded(savedInstanceState.getBoolean(EXPANDED, false))
+ viewModel.setIsDeparture(savedInstanceState.getBoolean(DEPARTURE, true))
+ viewModel.setFromLocation(fromLocation.getLocation())
+ viewModel.setViaLocation(viaLocation.getLocation())
+ viewModel.setToLocation(toLocation.getLocation())
+ viewModel.onTimeAndDateSet(savedInstanceState.getSerializable(DATE) as Calendar)
+ }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.directions, menu)
+ expandItem = menu.findItem(R.id.action_navigation_expand)
+ super.onCreateOptionsMenu(menu, inflater)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ R.id.action_navigation_expand -> {
+ viewModel.setIsExpanded(!item.isChecked)
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ private fun onCalendarUpdated(calendar: Calendar?) {
+ if (calendar == null) return
+ when {
+ isNow(calendar) -> {
+ time.setText(R.string.now)
+ date.visibility = GONE
+ }
+ DateUtils.isToday(calendar) -> {
+ time.text = getTime(context, calendar.time)
+ date.visibility = GONE
+ }
+ else -> {
+ time.text = getTime(context, calendar.time)
+ date.text = getDate(context, calendar.time)
+ date.visibility = VISIBLE
+ }
+ }
+ }
+
+ private fun swapLocations() {
+ val toToY = fromCard.y - toCard.y
+ val slideUp = TranslateAnimation(
+ RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF,
+ 0.0f, Animation.ABSOLUTE, toToY
+ )
+ slideUp.duration = 400
+ slideUp.fillAfter = true
+ slideUp.isFillEnabled = true
+
+ val fromToY = toCard.y - fromCard.y
+ val slideDown = TranslateAnimation(
+ RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF,
+ 0.0f, Animation.ABSOLUTE, fromToY
+ )
+ slideDown.duration = 400
+ slideDown.fillAfter = true
+ slideDown.isFillEnabled = true
+
+ fromCard.startAnimation(slideDown)
+ toCard.startAnimation(slideUp)
+
+ slideUp.setAnimationListener(object : Animation.AnimationListener {
+ override fun onAnimationStart(animation: Animation) {}
+
+ override fun onAnimationRepeat(animation: Animation) {}
+
+ override fun onAnimationEnd(animation: Animation) {
+ // swap location objects
+ val tmp = toLocation.getLocation()
+ if (fromLocation.isSearching) {
+ viewModel.findGpsLocation.setValue(null)
+ // TODO: GPS currently only supports from location, so don't swap it for now
+ viewModel.setToLocation(null)
+ } else {
+ viewModel.setToLocation(fromLocation.getLocation())
+ }
+ viewModel.setFromLocation(tmp)
+
+ fromCard.clearAnimation()
+ toCard.clearAnimation()
+
+ viewModel.search()
+ }
+ })
+ }
+
+ private fun onIsDepartureChanged(isDeparture: Boolean) {
+ departureIcon.setImageResource(if (isDeparture) R.drawable.ic_trip_departure else R.drawable.ic_trip_arrival)
+ }
+
+ private fun onViaVisibleChanged(viaVisible: Boolean) {
+ expandItem?.isChecked = viaVisible
+ expandItem?.setIcon(if (viaVisible) R.drawable.ic_action_navigation_unfold_less_white else R.drawable.ic_action_navigation_unfold_more_white)
+ viaCard.visibility = if (viaVisible) VISIBLE else GONE
+ }
+
+ private fun onFindGpsLocation(type: FavLocationType?) {
+ if (type == null) {
+ viewModel.locationLiveData.removeObservers(this@DirectionsFragment)
+ fromLocation.clearSearching()
+ return
+ }
+ if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) {
+ return
+ }
+ fromLocation.setSearching()
+ toLocation.requestFocus()
+ viewModel.locationLiveData.observe(this, Observer { location ->
+ viewModel.setFromLocation(location)
+ viewModel.search()
+ viewModel.locationLiveData.removeObservers(this@DirectionsFragment)
+ })
+ }
+
+ private fun onFavStatusChanged(isFav: Boolean?) {
+ if (isFav == null) {
+ favIcon.visibility = INVISIBLE
+ } else {
+ favIcon.visibility = VISIBLE
+ if (isFav) {
+ favIcon.setImageResource(R.drawable.ic_action_star)
+ } else {
+ favIcon.setImageResource(R.drawable.ic_action_star_empty)
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsViewModel.java b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsViewModel.java
index 3b0acd524..fb5dcee7f 100644
--- a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsViewModel.java
+++ b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsViewModel.java
@@ -164,6 +164,11 @@ LiveData getIsDeparture() {
return isDeparture;
}
+ void toggleDeparture() {
+ isDeparture.setValue(!(isDeparture.getValue() == null || isDeparture.getValue()));
+ search();
+ }
+
void setIsDeparture(boolean departure) {
isDeparture.setValue(departure);
search();
diff --git a/app/src/main/res/drawable/ic_action_navigation_unfold_less_white.xml b/app/src/main/res/drawable/ic_action_navigation_unfold_less_white.xml
new file mode 100644
index 000000000..6160ae372
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_navigation_unfold_less_white.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_action_navigation_unfold_more_white.xml b/app/src/main/res/drawable/ic_action_navigation_unfold_more_white.xml
new file mode 100644
index 000000000..46ba28c6d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_action_navigation_unfold_more_white.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_trip_arrival.xml b/app/src/main/res/drawable/ic_trip_arrival.xml
new file mode 100644
index 000000000..a7b88c3cf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_trip_arrival.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_trip_departure.xml b/app/src/main/res/drawable/ic_trip_departure.xml
new file mode 100644
index 000000000..0cd27a357
--- /dev/null
+++ b/app/src/main/res/drawable/ic_trip_departure.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/fragment_directions_form.xml b/app/src/main/res/layout/fragment_directions_form.xml
index 706190b11..9f32c3f2e 100644
--- a/app/src/main/res/layout/fragment_directions_form.xml
+++ b/app/src/main/res/layout/fragment_directions_form.xml
@@ -7,6 +7,7 @@
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:paddingBottom="8dp"
+ tools:context=".trips.search.DirectionsActivity"
tools:showIn="@layout/activity_directions">
-
-
-
-
-
-
-
-
-
+
@@ -142,4 +96,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/directions.xml b/app/src/main/res/menu/directions.xml
index fcde4807c..b4a3ff6b6 100644
--- a/app/src/main/res/menu/directions.xml
+++ b/app/src/main/res/menu/directions.xml
@@ -1,44 +1,13 @@
-