diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b67c3cbc..c9564a6a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,6 +26,9 @@ + diff --git a/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenter.kt b/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenter.kt index c1fbe41f..806d635a 100644 --- a/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenter.kt +++ b/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenter.kt @@ -13,6 +13,7 @@ public interface MainPresenter { public fun onSearchResultSelected(position: Int) public fun onExpandSearchView() public fun onCollapseSearchView() + public fun onShowDirectionList() public fun onQuerySubmit() public fun onViewAllSearchResults() public fun onBackPressed() diff --git a/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenterImpl.kt b/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenterImpl.kt index 55cae212..67b4664a 100644 --- a/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenterImpl.kt +++ b/app/src/main/kotlin/com/mapzen/erasermap/presenter/MainPresenterImpl.kt @@ -77,4 +77,8 @@ public class MainPresenterImpl() : MainPresenter { viewController?.shutDown() } } + + override fun onShowDirectionList() { + viewController?.showDirectionList() + } } diff --git a/app/src/main/kotlin/com/mapzen/erasermap/util/DisplayHelper.kt b/app/src/main/kotlin/com/mapzen/erasermap/util/DisplayHelper.kt new file mode 100644 index 00000000..4d198928 --- /dev/null +++ b/app/src/main/kotlin/com/mapzen/erasermap/util/DisplayHelper.kt @@ -0,0 +1,21 @@ +package com.mapzen.erasermap.util + +import android.content.Context +import com.mapzen.erasermap.R + +public object DisplayHelper { + + /** + * Fetch the resource drawable ID of the turn icon for the given instruction and style. + + * @param context current context in which to display the icon. + * * + * @param turnInstruction the integer value representing this turn instruction. + * * + * @return the resource ID of the turn icon to display. + */ + public fun getRouteDrawable(context: Context, turnInstruction: Int?): Int { + var drawableId = context.getResources().getIdentifier("ic_route_" + turnInstruction, "drawable", context.getPackageName()) + return drawableId + } +} diff --git a/app/src/main/kotlin/com/mapzen/erasermap/view/InstructionListActivity.kt b/app/src/main/kotlin/com/mapzen/erasermap/view/InstructionListActivity.kt new file mode 100644 index 00000000..4f95cc63 --- /dev/null +++ b/app/src/main/kotlin/com/mapzen/erasermap/view/InstructionListActivity.kt @@ -0,0 +1,136 @@ +package com.mapzen.erasermap.view + +import android.content.Context +import android.opengl.Visibility +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ListView +import android.widget.TextView +import android.widget.ImageView +import com.mapzen.erasermap.R +import com.mapzen.erasermap.util.DisplayHelper +import com.mapzen.pelias.SimpleFeature +import com.mapzen.valhalla.Instruction +import com.mapzen.helpers.DistanceFormatter +import java.util.ArrayList + +public class InstructionListActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_instructions) + getSupportActionBar()?.hide() + val listView = findViewById(R.id.instruction_list_view) as ListView + findViewById(R.id.route_reverse).setVisibility(View.GONE) + val bundle = getIntent()?.getExtras() + val instruction_strings: ArrayList? = bundle?.getStringArrayList("instruction_strings") + val instruction_types: ArrayList? = bundle?.getIntegerArrayList("instruction_types") + val instruction_distances: ArrayList? = bundle?.getIntegerArrayList("instruction_distances") + val reverse : Boolean = bundle?.getBoolean("reverse") as Boolean + setHeaderOrigins(bundle, reverse) + if (instruction_strings != null) { + listView.setAdapter(DirectionListAdapter(this, instruction_strings, instruction_types, instruction_distances, reverse)) + listView.setOnItemClickListener { parent, view, position, id -> + setResult(position) + finish() + } + } + } + + private fun setHeaderOrigins(bundle: Bundle?, reverse: Boolean) { + if (reverse) { + (findViewById(R.id.starting_point) as TextView).setText(bundle?.getString("destination")) + (findViewById(R.id.destination) as TextView).setText(R.string.current_location) + findViewById(R.id.starting_location_icon).setVisibility(View.GONE) + findViewById(R.id.destination_location_icon).setVisibility(View.VISIBLE) + } else { + (findViewById(R.id.starting_point) as TextView).setText(R.string.current_location) + (findViewById(R.id.destination) as TextView).setText(bundle?.getString("destination")) + findViewById(R.id.starting_location_icon).setVisibility(View.VISIBLE) + findViewById(R.id.destination_location_icon).setVisibility(View.GONE) + } + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + setResult(-1) + finish() + return true + } + + private class DirectionListAdapter(context: Context, strings: ArrayList?, + types: ArrayList?, distances: ArrayList?, + reverse : Boolean) : BaseAdapter() { + private final var CURRENT_LOCATION_OFFSET = 1 + private var instruction_strings: ArrayList? = strings + private var instruction_types: ArrayList? = types + private var instruction_distances: ArrayList? = distances + private var context: Context = context + private var reverse : Boolean = reverse + + override fun getCount(): Int { + var size = if (instruction_strings != null) (instruction_strings!!.size() + + CURRENT_LOCATION_OFFSET) else 0 + return size + } + + override fun getItemId(position: Int): Long { + return 0 + } + + override fun getItem(position: Int): Any? { + return 0 + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { + var view: View = View.inflate(context, R.layout.direction_list_item, null) + if(reverse) { + setReversedDirectionListItem(position, view) + } else { + setDirectionListItem(position, view) + } + return view + } + + private fun setReversedDirectionListItem(position : Int, view : View) { + if(position == instruction_strings?.size()) { + setListItemToCurrentLocation(view) + } else { + var distanceVal : Int? = instruction_distances?.get(position) + var formattedDistance : String = DistanceFormatter.format( + (distanceVal?.toInt() as Int)) + var iconId : Int = DisplayHelper.getRouteDrawable(context, + instruction_types?.get(position)) + + (view.findViewById(R.id.simple_instruction) as TextView).setText( + instruction_strings?.get(position).toString()) + (view.findViewById(R.id.distance) as TextView).setText(formattedDistance) + (view.findViewById(R.id.icon) as ImageView).setImageResource(iconId) + } + } + + private fun setDirectionListItem(position : Int, view : View) { + if (position == 0 ) { + setListItemToCurrentLocation(view) + } else { + var distanceVal : Int? = instruction_distances?.get(position - CURRENT_LOCATION_OFFSET) + var formattedDistance : String = DistanceFormatter.format((distanceVal?.toInt() as Int)) + var iconId : Int = DisplayHelper.getRouteDrawable(context, + instruction_types?.get(position - CURRENT_LOCATION_OFFSET)) + + (view.findViewById(R.id.simple_instruction) as TextView).setText( + instruction_strings?.get(position - CURRENT_LOCATION_OFFSET).toString()) + (view.findViewById(R.id.distance) as TextView).setText(formattedDistance) + (view.findViewById(R.id.icon) as ImageView).setImageResource(iconId) + } + } + + private fun setListItemToCurrentLocation(view : View) { + (view.findViewById(R.id.simple_instruction) as TextView).setText(R.string.current_location) + (view.findViewById(R.id.icon) as ImageView).setImageResource(R.drawable.ic_locate) + } + } + +} diff --git a/app/src/main/kotlin/com/mapzen/erasermap/view/MainActivity.kt b/app/src/main/kotlin/com/mapzen/erasermap/view/MainActivity.kt index f82543cb..37ed57e5 100644 --- a/app/src/main/kotlin/com/mapzen/erasermap/view/MainActivity.kt +++ b/app/src/main/kotlin/com/mapzen/erasermap/view/MainActivity.kt @@ -68,6 +68,7 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback public val requestCodeSearchResults: Int = 0x01 + private var route: Route? = null; var locationClient: LostApiClient? = null @Inject set var tileCache: Cache? = null @@ -89,6 +90,8 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback var destination: Feature? = null var path: PathLayer? = null var markers: ItemizedLayer? = null + var type : Router.Type = Router.Type.DRIVING + var reverse : Boolean = false; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -102,6 +105,7 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback initPoiLayer() initAutoCompleteAdapter() initFindMeButton() + initreverseButton() centerOnCurrentLocation() presenter?.onRestoreViewState() } @@ -213,7 +217,6 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback listView.setEmptyView(emptyView) restoreCurrentSearchTerm() } - return true } @@ -407,16 +410,11 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback override fun showRoutePreview(feature: Feature) { this.destination = feature - val simpleFeature = SimpleFeature.fromFeature(feature) - val location = LocationServices.FusedLocationApi?.getLastLocation(); - if (location is Location) { - val start: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) - val dest: DoubleArray = doubleArrayOf(simpleFeature.getLat(), simpleFeature.getLon()) - getInitializedRouter().setLocation(start).setLocation(dest).setCallback(this).fetch() - } + route() } override fun success(route: Route?) { + this.route = route; runOnUiThread({ getSupportActionBar()?.hide() findViewById(R.id.route_preview).setVisibility(View.VISIBLE) @@ -478,7 +476,6 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback } catch (e: Exception) { Toast.makeText(this@MainActivity, "No route found", Toast.LENGTH_LONG).show() } - } private fun getMarkerItem(icon: Int, loc: Location, place: MarkerItem.HotspotPlace): MarkerItem { @@ -496,44 +493,68 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback findViewById(R.id.route_preview).setVisibility(View.GONE) } + fun route() { + val simpleFeature = SimpleFeature.fromFeature(destination) + val location = LocationServices.FusedLocationApi?.getLastLocation() + if (reverse) { + if (location is Location) { + val start: DoubleArray = doubleArrayOf(simpleFeature.getLat(), simpleFeature.getLon()) + val dest: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) + getInitializedRouter().setLocation(start).setLocation(dest).setCallback(this).fetch() + } + } else { + if (location is Location) { + val start: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) + val dest: DoubleArray = doubleArrayOf(simpleFeature.getLat(), simpleFeature.getLon()) + getInitializedRouter().setLocation(start).setLocation(dest).setCallback(this).fetch() + } + } + } fun updateRoutePreview(destination: Feature?) { - val dest = SimpleFeature.fromFeature(destination) (findViewById(R.id.by_car) as RadioButton).setOnCheckedChangeListener { compoundButton, b -> if (b) { - val location = LocationServices.FusedLocationApi?.getLastLocation(); - if (location is Location) { - val start: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) - val dest: DoubleArray = doubleArrayOf(dest.getLat(), dest.getLon()) - getInitializedRouter().setDriving().setLocation(start).setCallback(this).setLocation(dest).fetch(); - } + type = Router.Type.DRIVING + route() (findViewById(R.id.routing_circle) as ImageButton).setImageResource(R.drawable.ic_start_car_normal) } } (findViewById(R.id.by_foot) as RadioButton).setOnCheckedChangeListener { compoundButton, b -> if (b) { - val location = LocationServices.FusedLocationApi?.getLastLocation(); - if (location is Location) { - val start: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) - val dest: DoubleArray = doubleArrayOf(dest.getLat(), dest.getLon()) - getInitializedRouter().setWalking().setLocation(start).setLocation(dest).setCallback(this).fetch(); - } + type = Router.Type.WALKING + route() (findViewById(R.id.routing_circle) as ImageButton).setImageResource(R.drawable.ic_start_walk_normal) } } (findViewById(R.id.by_bike) as RadioButton).setOnCheckedChangeListener { compoundButton, b -> if (b) { - val location = LocationServices.FusedLocationApi?.getLastLocation(); - if (location is Location) { - val start: DoubleArray = doubleArrayOf(location.getLatitude(), location.getLongitude()) - val dest: DoubleArray = doubleArrayOf(dest.getLat(), dest.getLon()) - getInitializedRouter().setBiking().setLocation(start).setLocation(dest).setCallback(this).fetch() - } + type = Router.Type.BIKING + route() (findViewById(R.id.routing_circle) as ImageButton).setImageResource(R.drawable.ic_start_bike_normal) } } } + private fun reverse() { + reverse = !reverse; + (findViewById(R.id.route_preview) as RoutePreviewView).reverse = this.reverse + if(reverse) { + findViewById(R.id.starting_location_icon).setVisibility(View.GONE) + findViewById(R.id.destination_location_icon).setVisibility(View.VISIBLE) + } else { + findViewById(R.id.starting_location_icon).setVisibility(View.VISIBLE) + findViewById(R.id.destination_location_icon).setVisibility(View.GONE) + } + route() + } + + private fun initreverseButton() { + (findViewById(R.id.route_reverse) as ImageButton).setOnClickListener({ reverse()}) + + (findViewById(R.id.routing_circle) as ImageButton).setOnClickListener ( + {presenter?.onShowDirectionList()}) + } + override fun onBackPressed() { if ((findViewById(R.id.route_preview)).getVisibility() == View.VISIBLE) { mapController?.getMap()?.layers()?.remove(path) @@ -547,7 +568,31 @@ public class MainActivity : AppCompatActivity(), ViewController, Router.Callback finish() } + override fun showDirectionList() { + val instructionStrings = ArrayList() + val instructionType= ArrayList() + val instructionDistance= ArrayList() + for(instruction in route!!.getRouteInstructions() ) { + instructionStrings.add(instruction.getHumanTurnInstruction()) + instructionType.add(instruction.turnInstruction) + instructionDistance.add(instruction.distance) + } + val simpleFeature = SimpleFeature.fromFeature(destination) + val intent = Intent(this, javaClass()) + intent.putExtra("instruction_strings", instructionStrings) + intent.putExtra("instruction_types", instructionType) + intent.putExtra("instruction_distances", instructionDistance) + intent.putExtra("destination", simpleFeature.toString()) + intent.putExtra("reverse", this.reverse) + startActivityForResult(intent, requestCodeSearchResults) + } + private fun getInitializedRouter(): Router { - return Router().setApiKey(BuildConfig.VALHALLA_API_KEY); + when(type) { + Router.Type.DRIVING -> return Router().setApiKey(BuildConfig.VALHALLA_API_KEY).setDriving() + Router.Type.WALKING -> return Router().setApiKey(BuildConfig.VALHALLA_API_KEY).setWalking() + Router.Type.BIKING -> return Router().setApiKey(BuildConfig.VALHALLA_API_KEY).setBiking() + } } } + diff --git a/app/src/main/kotlin/com/mapzen/erasermap/view/RoutePreviewView.kt b/app/src/main/kotlin/com/mapzen/erasermap/view/RoutePreviewView.kt index 606bae64..e80cb1d9 100644 --- a/app/src/main/kotlin/com/mapzen/erasermap/view/RoutePreviewView.kt +++ b/app/src/main/kotlin/com/mapzen/erasermap/view/RoutePreviewView.kt @@ -15,14 +15,23 @@ import com.mapzen.valhalla.Router public class RoutePreviewView : RelativeLayout { + public var reverse : Boolean = false public var destination: SimpleFeature? = null set (destination) { - (findViewById(R.id.destination) as TextView).setText(destination?.getTitle()) + if(reverse) { + (findViewById(R.id.starting_point) as TextView).setText(destination?.getTitle()) + } else { + (findViewById(R.id.destination) as TextView).setText(destination?.getTitle()) + } } public var route: Route? = null set (route) { - (findViewById(R.id.starting_point) as TextView).setText(R.string.current_location) + if(reverse) { + (findViewById(R.id.destination) as TextView).setText(R.string.current_location) + } else { + (findViewById(R.id.starting_point) as TextView).setText(R.string.current_location) + } } public constructor(context: Context) : super(context) { diff --git a/app/src/main/kotlin/com/mapzen/erasermap/view/ViewController.kt b/app/src/main/kotlin/com/mapzen/erasermap/view/ViewController.kt index 530207bd..7598b2e9 100644 --- a/app/src/main/kotlin/com/mapzen/erasermap/view/ViewController.kt +++ b/app/src/main/kotlin/com/mapzen/erasermap/view/ViewController.kt @@ -4,6 +4,7 @@ import com.mapzen.pelias.gson.Feature public interface ViewController { public fun showSearchResults(features: List) + public fun showDirectionList() public fun centerOnCurrentFeature(features: List) public fun showAllSearchResults(features: List) public fun hideSearchResults() diff --git a/app/src/main/res/drawable-hdpi/ic_route_gr_1.png b/app/src/main/res/drawable-hdpi/ic_route_gr_1.png new file mode 100644 index 00000000..ac7ff8c0 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_route_gr_1.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_route_gr_1.png b/app/src/main/res/drawable-mdpi/ic_route_gr_1.png new file mode 100644 index 00000000..dbd5fda2 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_route_gr_1.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_route_gr_1.png b/app/src/main/res/drawable-xhdpi/ic_route_gr_1.png new file mode 100644 index 00000000..191f981d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_route_gr_1.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_route_gr_1.png b/app/src/main/res/drawable-xxhdpi/ic_route_gr_1.png new file mode 100644 index 00000000..2d384220 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_route_gr_1.png differ diff --git a/app/src/main/res/drawable/ic_route_0.png b/app/src/main/res/drawable/ic_route_0.png new file mode 100644 index 00000000..9dba9a92 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_0.png differ diff --git a/app/src/main/res/drawable/ic_route_1.png b/app/src/main/res/drawable/ic_route_1.png new file mode 100644 index 00000000..5f58a6d2 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_1.png differ diff --git a/app/src/main/res/drawable/ic_route_10.png b/app/src/main/res/drawable/ic_route_10.png new file mode 100644 index 00000000..2079d5b9 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_10.png differ diff --git a/app/src/main/res/drawable/ic_route_11.png b/app/src/main/res/drawable/ic_route_11.png new file mode 100644 index 00000000..3548d3c1 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_11.png differ diff --git a/app/src/main/res/drawable/ic_route_12.png b/app/src/main/res/drawable/ic_route_12.png new file mode 100644 index 00000000..d0e18d43 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_12.png differ diff --git a/app/src/main/res/drawable/ic_route_13.png b/app/src/main/res/drawable/ic_route_13.png new file mode 100644 index 00000000..3460cc41 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_13.png differ diff --git a/app/src/main/res/drawable/ic_route_14.png b/app/src/main/res/drawable/ic_route_14.png new file mode 100644 index 00000000..bab9d3f6 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_14.png differ diff --git a/app/src/main/res/drawable/ic_route_15.png b/app/src/main/res/drawable/ic_route_15.png new file mode 100644 index 00000000..0a095a2c Binary files /dev/null and b/app/src/main/res/drawable/ic_route_15.png differ diff --git a/app/src/main/res/drawable/ic_route_16.png b/app/src/main/res/drawable/ic_route_16.png new file mode 100644 index 00000000..ea4303ce Binary files /dev/null and b/app/src/main/res/drawable/ic_route_16.png differ diff --git a/app/src/main/res/drawable/ic_route_17.png b/app/src/main/res/drawable/ic_route_17.png new file mode 100644 index 00000000..7a12b6e2 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_17.png differ diff --git a/app/src/main/res/drawable/ic_route_18.png b/app/src/main/res/drawable/ic_route_18.png new file mode 100644 index 00000000..40e89482 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_18.png differ diff --git a/app/src/main/res/drawable/ic_route_19.png b/app/src/main/res/drawable/ic_route_19.png new file mode 100644 index 00000000..7bc73e4d Binary files /dev/null and b/app/src/main/res/drawable/ic_route_19.png differ diff --git a/app/src/main/res/drawable/ic_route_2.png b/app/src/main/res/drawable/ic_route_2.png new file mode 100644 index 00000000..6fb3a388 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_2.png differ diff --git a/app/src/main/res/drawable/ic_route_20.png b/app/src/main/res/drawable/ic_route_20.png new file mode 100644 index 00000000..1f2b0f4d Binary files /dev/null and b/app/src/main/res/drawable/ic_route_20.png differ diff --git a/app/src/main/res/drawable/ic_route_21.png b/app/src/main/res/drawable/ic_route_21.png new file mode 100644 index 00000000..eaa9e749 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_21.png differ diff --git a/app/src/main/res/drawable/ic_route_22.png b/app/src/main/res/drawable/ic_route_22.png new file mode 100644 index 00000000..dfbd56cc Binary files /dev/null and b/app/src/main/res/drawable/ic_route_22.png differ diff --git a/app/src/main/res/drawable/ic_route_23.png b/app/src/main/res/drawable/ic_route_23.png new file mode 100644 index 00000000..bf618865 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_23.png differ diff --git a/app/src/main/res/drawable/ic_route_24.png b/app/src/main/res/drawable/ic_route_24.png new file mode 100644 index 00000000..8e9dea7d Binary files /dev/null and b/app/src/main/res/drawable/ic_route_24.png differ diff --git a/app/src/main/res/drawable/ic_route_25.png b/app/src/main/res/drawable/ic_route_25.png new file mode 100644 index 00000000..c4dc5620 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_25.png differ diff --git a/app/src/main/res/drawable/ic_route_26.png b/app/src/main/res/drawable/ic_route_26.png new file mode 100644 index 00000000..b7f11f9e Binary files /dev/null and b/app/src/main/res/drawable/ic_route_26.png differ diff --git a/app/src/main/res/drawable/ic_route_27.png b/app/src/main/res/drawable/ic_route_27.png new file mode 100644 index 00000000..2b978ab2 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_27.png differ diff --git a/app/src/main/res/drawable/ic_route_28.png b/app/src/main/res/drawable/ic_route_28.png new file mode 100644 index 00000000..53c854bb Binary files /dev/null and b/app/src/main/res/drawable/ic_route_28.png differ diff --git a/app/src/main/res/drawable/ic_route_29.png b/app/src/main/res/drawable/ic_route_29.png new file mode 100644 index 00000000..7f669fb9 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_29.png differ diff --git a/app/src/main/res/drawable/ic_route_3.png b/app/src/main/res/drawable/ic_route_3.png new file mode 100644 index 00000000..75b40001 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_3.png differ diff --git a/app/src/main/res/drawable/ic_route_30.png b/app/src/main/res/drawable/ic_route_30.png new file mode 100644 index 00000000..f216e2ed Binary files /dev/null and b/app/src/main/res/drawable/ic_route_30.png differ diff --git a/app/src/main/res/drawable/ic_route_31.png b/app/src/main/res/drawable/ic_route_31.png new file mode 100644 index 00000000..b8652a10 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_31.png differ diff --git a/app/src/main/res/drawable/ic_route_32.png b/app/src/main/res/drawable/ic_route_32.png new file mode 100644 index 00000000..2f184a30 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_32.png differ diff --git a/app/src/main/res/drawable/ic_route_4.png b/app/src/main/res/drawable/ic_route_4.png new file mode 100644 index 00000000..1a9e26ca Binary files /dev/null and b/app/src/main/res/drawable/ic_route_4.png differ diff --git a/app/src/main/res/drawable/ic_route_5.png b/app/src/main/res/drawable/ic_route_5.png new file mode 100644 index 00000000..e8413f84 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_5.png differ diff --git a/app/src/main/res/drawable/ic_route_6.png b/app/src/main/res/drawable/ic_route_6.png new file mode 100644 index 00000000..3188ed62 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_6.png differ diff --git a/app/src/main/res/drawable/ic_route_7.png b/app/src/main/res/drawable/ic_route_7.png new file mode 100644 index 00000000..2d3b658a Binary files /dev/null and b/app/src/main/res/drawable/ic_route_7.png differ diff --git a/app/src/main/res/drawable/ic_route_8.png b/app/src/main/res/drawable/ic_route_8.png new file mode 100644 index 00000000..f7d1e6b2 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_8.png differ diff --git a/app/src/main/res/drawable/ic_route_9.png b/app/src/main/res/drawable/ic_route_9.png new file mode 100644 index 00000000..a7a15ec0 Binary files /dev/null and b/app/src/main/res/drawable/ic_route_9.png differ diff --git a/app/src/main/res/layout/activity_instructions.xml b/app/src/main/res/layout/activity_instructions.xml new file mode 100644 index 00000000..a5e80d42 --- /dev/null +++ b/app/src/main/res/layout/activity_instructions.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/direction_list_item.xml b/app/src/main/res/layout/direction_list_item.xml new file mode 100644 index 00000000..42d145e0 --- /dev/null +++ b/app/src/main/res/layout/direction_list_item.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_header_divider.xml b/app/src/main/res/layout/list_header_divider.xml new file mode 100644 index 00000000..5ffebbbf --- /dev/null +++ b/app/src/main/res/layout/list_header_divider.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/layout/list_item_instruction.xml b/app/src/main/res/layout/list_item_instruction.xml new file mode 100644 index 00000000..c6fd91fc --- /dev/null +++ b/app/src/main/res/layout/list_item_instruction.xml @@ -0,0 +1,11 @@ + + diff --git a/app/src/main/res/layout/route_header.xml b/app/src/main/res/layout/route_header.xml index c2019822..164ba620 100644 --- a/app/src/main/res/layout/route_header.xml +++ b/app/src/main/res/layout/route_header.xml @@ -94,7 +94,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="4dp" - android:src="@drawable/ic_pin_outline" + android:src="@drawable/ic_locate" android:visibility="gone" /> No recent searches %1$d of %2$d results Search Results + Instructions From: To: Current Location diff --git a/app/src/test/java/com/mapzen/erasermap/presenter/MainPresenterTest.java b/app/src/test/java/com/mapzen/erasermap/presenter/MainPresenterTest.java index b51cd43e..a2c49698 100644 --- a/app/src/test/java/com/mapzen/erasermap/presenter/MainPresenterTest.java +++ b/app/src/test/java/com/mapzen/erasermap/presenter/MainPresenterTest.java @@ -138,7 +138,12 @@ public void onBackPressed_shouldHideRoutePreview() throws Exception { presenter.onRoutePreviewEvent(new RoutePreviewEvent(getTestFeature())); presenter.onBackPressed(); assertThat(controller.isRoutePreviewVisible).isFalse(); + } + @Test + public void onShowDirectionList_shouldMakeDirectionsVisible(){ + presenter.onShowDirectionList(); + assertThat(controller.isDirectionListVisible).isTrue(); } private class TestViewController implements ViewController { @@ -148,6 +153,7 @@ private class TestViewController implements ViewController { private boolean isViewAllVisible; private boolean isSearchVisible; private boolean isRoutePreviewVisible; + private boolean isDirectionListVisible; @Override public void showSearchResults(@NotNull List features) { searchResults = (List) features; @@ -201,5 +207,8 @@ private class TestViewController implements ViewController { @Override public void shutDown() { } + + @Override + public void showDirectionList() { isDirectionListVisible = true;} } } diff --git a/app/src/test/java/com/mapzen/erasermap/view/InstructionListActivityTest.java b/app/src/test/java/com/mapzen/erasermap/view/InstructionListActivityTest.java new file mode 100644 index 00000000..878a2a39 --- /dev/null +++ b/app/src/test/java/com/mapzen/erasermap/view/InstructionListActivityTest.java @@ -0,0 +1,154 @@ +package com.mapzen.erasermap.view; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.mapzen.erasermap.BuildConfig; +import com.mapzen.erasermap.PrivateMapsTestRunner; +import com.mapzen.erasermap.R; +import com.mapzen.pelias.SimpleFeature; +import com.mapzen.valhalla.Route; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.fakes.RoboMenuItem; +import org.robolectric.shadows.ShadowActivity; +import org.robolectric.shadows.ShadowIntent; + +import java.io.IOException; + +import static com.mapzen.erasermap.dummy.TestHelper.getFixture; +import static com.mapzen.erasermap.dummy.TestHelper.getTestFeature; +import static org.assertj.core.api.Assertions.assertThat; +import static org.robolectric.Shadows.shadowOf; + +@RunWith(PrivateMapsTestRunner.class) +@Config(constants = BuildConfig.class, emulateSdk = 21) +public class InstructionListActivityTest { + private static MainActivity startActivity = Robolectric.setupActivity(MainActivity.class);; + private InstructionListActivity activity; + + @Before + public void setUp() throws Exception { + startActivity.setReverse(false); + startActivity.showRoutePreview(getTestFeature()); + startActivity.success(new Route(getFixture("valhalla_route"))); + startActivity.findViewById(R.id.routing_circle).performClick(); + ShadowActivity shadowActivity = shadowOf(startActivity); + Intent startedIntent = shadowActivity.getNextStartedActivity(); + activity = Robolectric.buildActivity(InstructionListActivity.class) + .withIntent(startedIntent).create().get(); + } + + public void setActivityToReverse() throws IOException, JSONException { + startActivity.setReverse(true); + startActivity.showRoutePreview(getTestFeature()); + try { + startActivity.success(new Route(getFixture("valhalla_route"))); + } catch (JSONException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + startActivity.findViewById(R.id.routing_circle).performClick(); + ShadowActivity shadowActivity = shadowOf(startActivity); + Intent startedIntent = shadowActivity.getNextStartedActivity(); + activity = Robolectric.buildActivity(InstructionListActivity.class) + .withIntent(startedIntent).create().get(); + } + + @Test + public void shouldNotBeNull() throws Exception { + assertThat(activity).isNotNull(); + } + + @Test + public void shouldHaveListView() throws Exception { + assertThat(activity.findViewById(R.id.instruction_list_view)).isNotNull(); + } + + @Test + public void onDirectionListOpen_shouldHaveOriginSet() throws Exception { + assertThat(((TextView)activity.findViewById(R.id.destination)).getText()) + .isEqualTo( SimpleFeature.fromFeature(startActivity.getDestination()).toString()); + assertThat(((TextView)activity.findViewById(R.id.starting_point)).getText()) + .isEqualTo(activity.getString(R.string.current_location)); + } + + @Test + public void onDirectionListOpenReversed_shouldHaveOriginSet() throws Exception { + setActivityToReverse(); + assertThat(((TextView) activity.findViewById(R.id.starting_point)).getText()) + .isEqualTo(SimpleFeature.fromFeature(startActivity.getDestination()).toString()); + assertThat(((TextView)activity.findViewById(R.id.destination)).getText()) + .isEqualTo(activity.getString(R.string.current_location)); + } + + @Test + public void onDirectionListOpen_shouldHaveCurrentLocationFirst() throws Exception { + View view = ((ListView) activity.findViewById(R.id.instruction_list_view)).getAdapter() + .getView(0, activity.findViewById(R.id.instruction_list_view), + getGenericViewGroup()); + + ImageView icon = (ImageView) view.findViewById(R.id.icon); + TextView instruction = (TextView) view.findViewById(R.id.simple_instruction); + TextView distance = (TextView) view.findViewById(R.id.distance); + + assertThat(icon.getDrawable()).isEqualTo(activity.getDrawable(R.drawable.ic_locate)); + assertThat(instruction.getText()).isEqualTo("Current Location"); + assertThat(distance.getText()).isEqualTo(""); + } + + @Test + public void onDirectionListOpen_shouldHaveFirstInstructionFirst() throws Exception { + View view = ((ListView) activity.findViewById(R.id.instruction_list_view)).getAdapter() + .getView(1, activity.findViewById(R.id.instruction_list_view), + getGenericViewGroup()); + + ImageView icon = (ImageView) view.findViewById(R.id.icon); + TextView instruction = (TextView) view.findViewById(R.id.simple_instruction); + TextView distance = (TextView) view.findViewById(R.id.distance); + + assertThat(icon.getDrawable()).isEqualTo(activity.getDrawable(R.drawable.ic_route_1)); + assertThat(instruction.getText()).contains("Go north on Adalbertstraße."); + assertThat(distance.getText()).isEqualTo("0.2 mi"); + } + + @Test + public void onDirectionListOpen_shouldHaveLastInstructionLast() throws Exception { + int pos = ((ListView) activity.findViewById(R.id.instruction_list_view)).getAdapter() + .getCount() - 1; + View view = ((ListView) activity.findViewById(R.id.instruction_list_view)).getAdapter() + .getView(pos, activity.findViewById(R.id.instruction_list_view), + getGenericViewGroup()); + + ImageView icon = (ImageView) view.findViewById(R.id.icon); + TextView instruction = (TextView) view.findViewById(R.id.simple_instruction); + TextView distance = (TextView) view.findViewById(R.id.distance); + + assertThat(icon.getDrawable()).isEqualTo(activity.getDrawable(R.drawable.ic_route_4)); + assertThat(instruction.getText()).contains("You have arrived at your destination."); + assertThat(distance.getText()).isEqualTo(""); + } + + @NotNull + private ViewGroup getGenericViewGroup() { + return new ViewGroup(activity.getApplicationContext()) { + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + + } + }; + } +} diff --git a/app/src/test/java/com/mapzen/erasermap/view/MainActivityTest.java b/app/src/test/java/com/mapzen/erasermap/view/MainActivityTest.java index 711ee66e..43736f62 100644 --- a/app/src/test/java/com/mapzen/erasermap/view/MainActivityTest.java +++ b/app/src/test/java/com/mapzen/erasermap/view/MainActivityTest.java @@ -27,15 +27,19 @@ import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import org.robolectric.fakes.RoboMenu; +import org.robolectric.shadows.ShadowActivity; +import org.robolectric.shadows.ShadowIntent; import org.robolectric.shadows.ShadowLocationManager; import org.robolectric.util.ReflectionHelpers; +import android.content.Intent; import android.content.SharedPreferences; import android.location.Location; import android.location.LocationManager; import android.preference.PreferenceManager; import android.support.v7.widget.SearchView; import android.view.Menu; +import android.view.View; import java.util.ArrayList; import static android.content.Context.LOCATION_SERVICE; @@ -379,6 +383,39 @@ public void onBack_shouldHideDrawnRoute() throws Exception { assertThat(activity.getMapController().getMap().layers().contains(activity.getPath())).isFalse(); } + @Test + public void onRadioClick_shouldChangeType() throws Exception { + activity.showRoutePreview(getTestFeature()); + activity.success(new Route(getFixture("valhalla_route"))); + activity.findViewById(R.id.route_preview).findViewById(R.id.by_bike).performClick(); + assertThat(activity.getType()).isEqualTo(Router.Type.BIKING); + activity.findViewById(R.id.route_preview).findViewById(R.id.by_foot).performClick(); + assertThat(activity.getType()).isEqualTo(Router.Type.WALKING); + activity.findViewById(R.id.route_preview).findViewById(R.id.by_car).performClick(); + assertThat(activity.getType()).isEqualTo(Router.Type.DRIVING); + } + + @Test + public void onReverseClick_shouldSetReverse() throws Exception { + activity.showRoutePreview(getTestFeature()); + activity.success(new Route(getFixture("valhalla_route"))); + assertThat(activity.getReverse()).isFalse(); + activity.findViewById(R.id.route_preview).findViewById(R.id.route_reverse).performClick(); + assertThat(activity.getReverse()).isTrue(); + } + + @Test + public void onRoutingCircleClick_shouldOpenDirectionListActivity() throws Exception { + activity.showRoutePreview(getTestFeature()); + activity.success(new Route(getFixture("valhalla_route"))); + assertThat(activity.findViewById(R.id.instruction_list_view)).isNull(); + activity.findViewById(R.id.routing_circle).performClick(); + ShadowActivity shadowActivity = shadowOf(activity); + Intent startedIntent = shadowActivity.getNextStartedActivity(); + ShadowIntent shadowIntent = shadowOf(startedIntent); + assertThat(shadowIntent.getComponent().getClassName()).contains("InstructionListActivity"); + } + @Test public void success_shouldAddMarkerLayer() throws Exception { activity.showRoutePreview(getTestFeature()); diff --git a/app/src/test/java/com/mapzen/erasermap/view/RoutePreviewViewTest.java b/app/src/test/java/com/mapzen/erasermap/view/RoutePreviewViewTest.java index f0ecc426..bba6d118 100644 --- a/app/src/test/java/com/mapzen/erasermap/view/RoutePreviewViewTest.java +++ b/app/src/test/java/com/mapzen/erasermap/view/RoutePreviewViewTest.java @@ -13,6 +13,7 @@ import org.junit.runner.RunWith; import org.robolectric.annotation.Config; +import android.view.View; import android.widget.TextView; import static com.mapzen.erasermap.dummy.TestHelper.getTestSimpleFeature; diff --git a/circle.yml b/circle.yml index 57f2960d..26a2f64e 100644 --- a/circle.yml +++ b/circle.yml @@ -8,6 +8,7 @@ machine: M2_HOME: $HOME/.m2/apache-maven-3.1.1/ M2: $HOME/.m2/apache-maven-3.1.1/bin/ ANDROID_HOME: /usr/local/android-sdk-linux + JAVA_OPTS: "-Xms256m -Xmx512m" dependencies: diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 07194838..00000000 --- a/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -org.gradle.jvmargs=-XX:MaxPermSize=1024m