Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

387 offline mappacks #417

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.pm.PackageManager

import net.cyclestreets.api.client.RetrofitApiClient
import net.cyclestreets.core.R
import kotlin.collections.Map

interface CycleStreetsApi {
fun getJourneyJson(plan: String, leaving: String?, arriving: String?, speed: Int, lonLat: DoubleArray): String
Expand All @@ -22,6 +23,7 @@ interface CycleStreetsApi {
fun getPOIs(key: String, lonW: Double, latS: Double, lonE: Double, latN: Double): List<POI>
fun getPOIs(key: String, lon: Double, lat: Double, radius: Int): List<POI>
fun getBlogEntries(): Blog
fun getMaps(): Maps
}

object ApiClient : CycleStreetsApi {
Expand Down Expand Up @@ -130,7 +132,9 @@ object ApiClient : CycleStreetsApi {
override fun getBlogEntries(): Blog {
return delegate.getBlogEntries()
}

override fun getMaps(): Maps {
return delegate.getMaps()
}
}

class ApiClientImpl(private val retrofitApiClient: RetrofitApiClient): CycleStreetsApi {
Expand Down Expand Up @@ -230,6 +234,10 @@ class ApiClientImpl(private val retrofitApiClient: RetrofitApiClient): CycleStre
return retrofitApiClient.blogEntries
}

override fun getMaps(): Maps {
return retrofitApiClient.maps
}

/////////////////////////////////////////////////////
private fun itineraryPoints(vararg lonLat: Double): String {
val sb = StringBuilder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package net.cyclestreets.api

data class Map(
val id: String,
Copy link
Member

@oliverlockwood oliverlockwood Jun 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

picky, but 8 characters indentation seems excessive.

Also I wonder if we would be better off naming this class differently - e.g. MapPack - so we don't confuse it with the native Map class in Kotlin and/or Java.
If you agree with this we could probably update the naming of the Maps class, and possible the getMaps method also.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now see it can't be MapPack as that would conflict.
What about MapReference or something similar; as effectively it acts as a reference to a downloadable map pack?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with MapPack, realised, changed to Map as a holding name, now considering DownloadableMap

val name: String,
val url: String,
val parent: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.cyclestreets.api

import android.os.AsyncTask

class Maps(
private val packs: Collection<Map>
): Iterable<Map> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would read easier as a one-liner rather than these 3 lines, but maybe that's just me.

val size get() = packs.size
override operator fun iterator() = packs.iterator()

companion object {
private var loaded_: Maps? = null

fun get(): Maps? {
if (loaded_ == null)
backgroundLoad()
return loaded_
} // get


private fun backgroundLoad() {
GetMapsTask().execute()
}

private class GetMapsTask : AsyncTask<Void?, Void?, Maps?>() {
override fun doInBackground(vararg params: Void?): Maps? {
return load()
}

override fun onPostExecute(maps: Maps?) {
loaded_ = maps
}
}

private fun load(): Maps? {
try {
return ApiClient.getMaps()
} catch (e: Exception) {
println(e.message)
}
return null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import net.cyclestreets.api.Blog;
import net.cyclestreets.api.GeoPlaces;
import net.cyclestreets.api.Maps;
import net.cyclestreets.api.POI;
import net.cyclestreets.api.POICategories;
import net.cyclestreets.api.PhotomapCategories;
Expand All @@ -24,6 +25,7 @@
import net.cyclestreets.api.client.dto.UserCreateResponseDto;
import net.cyclestreets.api.client.dto.UserJourneysDto;
import net.cyclestreets.api.client.geojson.GeoPlacesFactory;
import net.cyclestreets.api.client.geojson.MapsFactory;
import net.cyclestreets.api.client.geojson.PhotosFactory;
import net.cyclestreets.api.client.geojson.PoiFactory;

Expand Down Expand Up @@ -222,6 +224,11 @@ public UserJourneys getUserJourneys(final String username) throws IOException {
return response.body().toUserJourneys();
}

public Maps getMaps() throws IOException {
Response<FeatureCollection> response = v2Api.getMaps().execute();
return MapsFactory.Companion.toMaps(response.body());
}

public Result register(final String username,
final String password,
final String name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Call<FeatureCollection> geoCoder(@Query("q") String search,
@GET("/v2/journeys.user?format=flat&datetime=friendly")
Call<UserJourneysDto> getUserJourneys(@Query("username") String username);

@GET("/v2/mapdownloads.list")
Call<FeatureCollection> getMaps();

@FormUrlEncoded
@POST("/v2/user.create")
Call<UserCreateResponseDto> register(@Field("username") String username,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class AbstractObjectFactory {
@SuppressWarnings("unchecked")
protected static <V> V propertyOrDefault(Feature feature, String propertyName, V defaultValue) {
static <V> V propertyOrDefault(Feature feature, String propertyName, V defaultValue) {
return (feature.getProperty(propertyName) == null) ? defaultValue : (V)feature.getProperty(propertyName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.cyclestreets.api.client.geojson

import net.cyclestreets.api.Map
import net.cyclestreets.api.Maps
import net.cyclestreets.api.client.geojson.AbstractObjectFactory.propertyOrDefault
import org.geojson.Feature
import org.geojson.FeatureCollection

class MapsFactory {
companion object {
fun toMaps(featureCollection: FeatureCollection): Maps {
return Maps(
featureCollection.features
.map { f -> toMap(f) }
.filter { m -> isBritainOrIreland(m) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this restriction as a starting point. We can consider adding others subsequently as part of #46.

)
}

private fun toMap(feature: Feature): Map {
return Map(
feature.getProperty("id"),
feature.getProperty("name"),
feature.getProperty("url"),
propertyOrDefault(feature, "parent", "")
)
}

private fun isBritainOrIreland(m: Map): Boolean {
return isBritainOrIreland(m.id)
}
private fun isBritainOrIreland(p: String): Boolean {
return p.contains("great-britain") || p.contains("ireland")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object MainSupport {
fun switchMapFile(intent: Intent, context: Context): Boolean {
val mapPackage = intent.getStringExtra("mapfile") ?: return false
val pack = MapPack.findByPackage(context, mapPackage) ?: return false
CycleStreetsPreferences.enableMapFile(pack.path())
CycleStreetsPreferences.enableMapFile(pack.path)
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
}

private fun populateMapFileList(mapfilePref: ListPreference) {
val names = MapPack.availableMapPacks(context).map { pack: MapPack -> pack.name() }
val files = MapPack.availableMapPacks(context).map { pack: MapPack -> pack.path() }
val names = MapPack.availableMapPacks(context).map { pack: MapPack -> pack.name }
val files = MapPack.availableMapPacks(context).map { pack: MapPack -> pack.path }
mapfilePref.entries = names.toTypedArray()
mapfilePref.entryValues = files.toTypedArray()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static ITileSource mapRenderer(final Context context) {
if (renderer instanceof MapsforgeOSMTileSource) {
final String mapFile = CycleStreetsPreferences.mapfile();
final MapPack pack = MapPack.findByPackage(context, mapFile);
if (pack.current())
if (pack.getCurrent())
((MapsforgeOSMTileSource)renderer).setMapFile(mapFile);
else {
MessageBox.YesNo(context,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package net.cyclestreets.util

import android.content.Context
import android.content.Intent
import android.net.Uri
import net.cyclestreets.api.Maps
import net.cyclestreets.api.Map
import java.io.File
import java.io.FileInputStream
import java.io.FilenameFilter
import java.io.IOException
import java.util.*

class MapPack private constructor(
private val map: Map
) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would read easier as a one-liner rather than these 3 lines, but maybe that's just me.

val name get() = map.name
val path get() = "none"
val current get() = false

private class CycleStreetsMapFilter : FilenameFilter {
override fun accept(dir: File, name: String): Boolean {
return name.contains("net.cyclestreets.maps")
}
}

companion object {
@JvmStatic
fun searchGooglePlay(context: Context) {
val play = Intent(Intent.ACTION_VIEW)
play.data = Uri.parse("market://search?q=net.cyclestreets")
context.startActivity(play)
}

fun availableMapPacks(context: Context?): List<MapPack> {
val maps = Maps.get() ?: return emptyList()

return maps.map {m -> MapPack(m) }
}

@JvmStatic
fun findByPackage(context: Context?, packageName: String?): MapPack? {
for (pack in availableMapPacks(context)) if (pack.path.contains(packageName!!)) return pack
return null
}

private fun findMapFile(mapDir: File, prefix: String): File? {
for (c in mapDir.listFiles()) if (c.name.startsWith(prefix)) return c
return null
}

private fun mapProperties(mapDir: File): Properties {
val details = Properties()
try {
val detailsFile = findMapFile(mapDir, "patch.")
details.load(FileInputStream(detailsFile))
} catch (e: IOException) {
} catch (e: RuntimeException) {
}
return details
}
}
}