Merge branch 'follow-route' into RecyclerView

# Conflicts:
#	app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java
This commit is contained in:
sebas
2021-01-06 13:23:58 +01:00
33 changed files with 1384 additions and 134 deletions

View File

@@ -26,6 +26,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
repositories {
maven { url "https://jitpack.io" }
}
}
dependencies {
@@ -47,6 +50,10 @@ dependencies {
//osm
implementation 'org.osmdroid:osmdroid-android:6.1.8'
//osm bonus pack
implementation 'com.github.MKergall:osmbonuspack:6.6.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
testImplementation 'org.mockito:mockito-core:2.7.22'
}

View File

@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"

View File

@@ -2,134 +2,134 @@
{
"name":"McDonald's Breda Karnemelkstraat",
"coordinates":"51.58596318905295,4.77586651481887",
"description":"Wist je dat McDonalds de grootste restaurantketen ter wereld is? Hierdoor hebben we een indrukwekkende geschiedenis. Maar wij kijken liever naar onze toekomst. Nieuwe restaurants, betere producten en duurzaam ondernemen. Wil je meer weten over McDonalds? Lees verder op: https://www.mcdonalds.com/nl/nl-nl/over-ons.html!",
"imageUrl":"mc_donalds"
"description":"McDonald's restaurant",
"imageUrl":"NULL"
},
{
"name":"Subway Karnemelkstraat 10 A, 1",
"coordinates":"51.58632782568612,4.775219531501114",
"description":"Subway is een Amerikaanse multinationale fastfoodketen die voornamelijk sandwiches verkoopt. Het bedrijf onderscheidt zich van veel andere broodjeszaken doordat de klant zelf de sandwich kan laten samenstellen. Subway werkt met franchisenemers. Het bedrijf heeft bijna 45.000 vestigingen in alle werelddelen.",
"imageUrl":"subway"
"description":"4811 KJ Breda",
"imageUrl":"NULL"
},
{
"name":"Wok To Go Halstraat 40",
"coordinates":"51.58650312572897,4.777467069592386",
"description":"Bij Wok To Go houden we van snelle, gezonde en smaakvolle maaltijden. Sinds 2003 ontwikkelen onze chef-koks de lekkerste wokgerechten met verse ingrediënten. We doen dit vól overgave onder het motto “Making people happy through food”. Door het roerbakken met een kleine hoeveelheid olie op grote hitte, blijven de smaak en gezonde voedingsstoffen bewaard. We kiezen voor gezonde en unieke ingrediënten en bereiden uitgebalanceerde gerechten in een Wokki box voor een gezonde levensstijl.",
"imageUrl":"wok_to_go"
"description":"4811HX Breda",
"imageUrl":"NULL"
},
{
"name":"De Boterhal Grote Markt 19",
"coordinates":"51.588069667604756,4.7762685632180695",
"description":"De Boterhal in Breda is een internationaal tapasrestaurant, speciaalbiercafé en wijnbar. Men kan gezellig bij ons lunchen, borrelen en dineren. Wij hebben een uitgebreide menukaart met een hele hoop bieren, wijnen, zowel per glas als per fles te verkrijgen, lunch en tapasgerechtjes. Naast het eten wat wij serveren hebben we ook een hoop bieren en wijnen. Naast de bieren op de kaart hebben wij wisselende bieren; vijf ketelbieren en vijf seizoensbieren.",
"imageUrl":"de_boter_hal"
"description":"4811XL Breda",
"imageUrl":"NULL"
},
{
"name":"Gauchos Grote Markt 33",
"coordinates":"51.58859328857082,4.77601349563689",
"description":"De middeleeuwse Grote Markt is een historische plek in het Bourgondische hart van Breda, ooit in handen van de Spaanse bezetter. Gauchos Grill-Restaurant combineert daar Brabantse gemoedelijkheid met professionele gastvrijheid. In onze Latijnse keuken bereiden wij op uw aanwijzing een malse Argentijnse steak of een smakelijk visgerecht van de grill.",
"imageUrl":"gauchos"
"description":"4811XP Breda",
"imageUrl":"NULL"
},
{
"name":"The Tosti Club Breda A4, Vlaszak 2",
"coordinates":"51.58905632735254,4.780729463841719",
"description":"Je kunt bij al onze vestigingen de hele dag terecht, want bij The Tosti Club eet je het klokje rond. Dus kom gezellig ontbijten, lunchen of voor een snelle hap aan het einde van de dag (wat dacht je van onze The Tosti Slice, onze variant op pizza!). Even geen zin in brood? Dan kunnen we je ook verblijden met onder andere acaï smoothiebowls, pancakes, granolas / yoghurt of gewoon een lekkere warme drank met gebak. Mogen we je de Red Velvet fudge cake aanraden?",
"imageUrl":"the_tosti_club"
"description":"4811GR Breda",
"imageUrl":"NULL"
},
{
"name":"Coffee & Lunch 4 you Oude Vest 31",
"coordinates":"51.58741730235298,4.779832967540571",
"description":"Welkom bij Coffee & Lunch 4 you! Onze sfeervolle lunchroom is gelegen in het centrum van Breda, in de directe nabijheid van de parkeergarage en de fietsenstalling.",
"imageUrl":"coffee_and_lunch"
"description":"4811HS Breda",
"imageUrl":"NULL"
},
{
"name":"t Zusje Breda Vismarktstraat 28",
"coordinates":"51.590133292554434,4.773911506170458",
"description":"Dat is een avond bij t Zusje. Gezellig samenzijn in een huiselijke sfeer en genieten van onze kleine gerechtjes, die je de hele avond kunt bestellen. Bij t Zusje ben je thuis: jij bepaalt zelf de invulling van de avond.\nWe horen graag wat je wensen zijn, vinden het leuk je te verrassen met bijzondere gerechtjes en zetten graag die extra stap. We bieden je een avond uit, zoals wij die zelf ook graag zien. Avondvullend Bourgondisch genieten? In het prachtige pand van ons Zusje in Breda beleef je een gezellige avond met avondvullend tapas eten voor 31,80.\nBel snel en reserveer!",
"imageUrl":"t_zusje_breda"
"description":"4811WE Breda",
"imageUrl":"NULL"
},
{
"name":"VR-World Nassaustraat 2",
"coordinates":"51.5913566342086,4.786256804321071",
"description":"Virtual Reality is hét uitje van dit moment. Zombies verslaan, vuurballen schieten of met laserzwaarden vechten, met Virtual Reality is niks te gek. Bij VR World zijn we elke dag opzoek naar de nieuwste experiences voor jullie.\n\nWat dacht je bijvoorbeeld van een Escape Room, maar dan in Virtual Reality? Bij VR World bieden wij de nieuwste Escapes aan op het gebied van Virtual Reality. Ontsnap bijvoorbeeld uit een Piramide of ontmantel een raket. Durf jij deze uitdaging aan?\n\nVR World is gelegen op een unieke locatie, namelijk de koepelgevangenis van Breda. Deze gevangenis was tot 2016 nog in werking en daarna hebben bedrijven er hun intrek genomen, zo ook VR World.",
"imageUrl":"vr_world"
"description":"4811DD Breda",
"imageUrl":"NULL"
},
{
"name":"Kees Kroket Houtmarkt 9",
"coordinates":"51.58647180329833,4.77741809637617",
"description":"KEEEEES KROKET! Al meer dan tien jaar is Kees Kroket in het centrum van Breda gevestigd, vlakbij het winkelend publiek. Eerst in de welbekende Houtmarktpassage en sinds april 2019 zijn we gevestigd op onze nieuwe locatie aan de Houtmarkt 9. U proeft de kwaliteit bij onze verse frites. Deze, uit de Agria aardappel gesneden frites, wordt in zonnebloemolie voorgebakken en in een mix van plantaardige oliën afgebakken. Dit zorgt niet alleen voor de heerlijke smaak maar ook dat onze frites relatief weinig verzadigde vetten en transvetzuren bevat, waardoor we van het beeldmerk Verantwoord Frituren gebruik mogen maken.",
"imageUrl":"kees_kroket"
"description":"KEEEEES KROKET!",
"imageUrl":"NULL"
},
{
"name":"Prison Escape Kloosterlaan 168",
"coordinates":"51.59073795635181,4.784917104321059",
"description":"Prison Escape duurt in het totaal 3 uur en je hebt als doel om te ontsnappen uit de zwaarbewaakte gevangenis. Een cast van 25 acteurs brengt de ervaring tot leven en het is aan jou om een weg naar buiten te vinden. In de gevangenis zijn verschillende objecten verstopt die het wellicht makkelijker zouden kunnen maken om de weg naar buiten te realiseren.\n\nWees op je hoede, kijk goed om je heen, vertrouw (bijna) niemand en stap op mensen af..\nDe klok tikt en jij hebt 1 doel: de weg naar de vrijheid vinden.",
"imageUrl":"prison_escape_room"
"description":"4811EE Breda",
"imageUrl":"NULL"
},
{
"name":"De Koepel - FutureDome Events Nassausingel 26",
"coordinates":"51.590431588532105,4.786756741648511",
"description":"n groepen word je onder begeleiding van een van onze gidsen rondgeleid langs de meest unieke en mooiste monumentale plekken in en rondom de Koepel!\n\u200B\n\nDe gids zal hierbij op de verschillende locaties toelichting geven over het roemruchte verleden. De rondleiding over het gevangenisterrein brengt u onder andere langs de koepel, de authentieke kapel, vrouwengevangenis, verschillende luchtplaatsen en het oude gerechtsgebouw.",
"imageUrl":"de_koepel_future_events"
"description":"4811HP Breda",
"imageUrl":"NULL"
},
{
"name":"Escaping Breda: Escape Room Games Boschstraat 114",
"coordinates":" 51.59110835530862,4.784147222780912",
"description":"Escaping Breda is een nieuwe moderne locatie en heeft op dit moment 2 avontuurlijke escape rooms. Daarnaast komen er volgend jaar nog 2 extra escape rooms bij. \n\nOntsnap uit de spannende escape room Lets Rob The Bank, een kamer geschikt voor volwassenen én kinderen. Ontsnap je liever uit een escape room met een hoger spannings- en spelniveau? Kies dan voor Patient X.\n\nOp onze locatie in Breda hebben we ook een gezellig boardgame café. Combineer je ontsnapping met een drankje, hapje en alle gratis boardgames.\n\nEscaping Breda is de perfecte plek voor een uitje met je familie, vrienden of collegas.",
"imageUrl":"escaping_room"
"description":"4811GK Breda",
"imageUrl":"NULL"
},
{
"name":"MEZZ Breda Keizerstraat 101",
"coordinates":"51.58394697737321,4.779757901349616",
"description":"MEZZ is een open club, betrokken, nieuwsgierig en onderzoekend. MEZZ heeft humor, is gevat, soms provocatief en verrassend. Beleving en plezier staan centraal waarbij wij bottom up denken. Wij zijn er voor jou, jouw MEZZ. Heb je ideeën of wil je meer weten, neem contact op. Wij reageren altijd.",
"description":"4811HL Breda",
"imageUrl":"mezz_breda"
},
{
"name":"Het Klooster Breda Schorsmolenstraat 13",
"coordinates":"51.58775443759389,4.765568874365066",
"description":"In dit oude Kapucijnenklooster wordt een woon- en werkgemeenschap gevestigd onder de naam\n”Het Klooster Breda”. \nMet de inkomsten uit bedrijvigheid wordt 12 mensen die dakloos zijn onderdak geboden, van waaruit zij zich weer een plek in de samenleving kunnen verwerven.",
"imageUrl":"het_klooster_breda"
"description":"4811VN Breda",
"imageUrl":"NULL"
},
{
"name":"Beach & Lounge club Spider “rooftop bar” Nieuwe Prinsenkade",
"coordinates":"51.59212977605884,4.774043765582372",
"description":"Beach & Lounge Club Spider staat bekent om zijn immens populaire locatie in Bergen op Zoom. Sinds 2020 heeft deze hoog segment lounge club een tweede locatie geopend in Breda genaamd Beach & Lounge Club Spider Rooftop Bar.",
"imageUrl":"beach_and_lounge_club"
"description":"4811VC Breda",
"imageUrl":"NULL"
},
{
"name":"Koningin Wilhelmina Paviljoen Kraanstraat 4b",
"coordinates":"51.590645369292396,4.776045124415531",
"description":"Koningin Wilhelmina Paviljoen is een bouwwerk in Breda Centrum in Breda. Het behoort tot de Koninklijke Militaire Academie (KMA) en bezit de status van rijksmonument. Het staat aan het Kasteelplein 15, vlak voor het Kasteel van Breda. Het ligt met de voorgevel aan de westkant van de oprijlaan van het kasteel, met de lange rechterzijgevel aan de kasteelgracht en de lange linkerzijgevel aan de Cingelstraat.",
"imageUrl":"koningin_wilhelimna_paviljoen"
"description":"4811XV Breda",
"imageUrl":"NULL"
},
{
"name":"Hercules en de Nemeïsche leeuw",
"coordinates":"51.59130522182325,4.778161739135078",
"description":"Het beeld toont Hercules met de huid van de Nemeïsche leeuw. Herakles of Hercules is een figuur uit de Griekse mythologie. Hij was een Griekse heros en werd beroemd om de 12 moeilijke werken die hij uitvoerde in opdracht van koning Eurystheus. Het beeld maakt onderdeel uit van 17 anderen zandstenen beelden die Willem III tussen 1670 en 1686 kocht. De beelden stonden verdeeld over grasperken in het Valkenberg park.\nHercules is het enige originele beeld dat overgebleven is.",
"imageUrl":"hercules_park_valkenburg"
"description":"4811XJ Breda",
"imageUrl":"NULL"
},
{
"name":"Nassau-Baroniemonument - 1905 - Pierre Cuypers Delpratsingel 1",
"coordinates":"51.592530636759136,4.780278353833301",
"description":"Het Baroniemonument of Nassau-Baroniemonument is een beeld van de Nederlandse architect Pierre Cuypers. Het staat in het Park Valkenberg in Breda. Het monument werd geplaatst ter herinnering aan de 500-jarige band (1904) tussen Breda en het huis Oranje-Nassau. In 1404 werd Engelbrecht I van Nassau-Siegen gehuldigd als heer van Breda.",
"imageUrl":"nassau_baroniemonument"
"description":"4811AM Breda",
"imageUrl":"NULL"
},
{
"name":"Station Breda Gravinnen van Nassauboulevard 43",
"coordinates":"51.59569850758307,4.780295549958155",
"description":"Station Breda is het centrale spoorwegstation van de Nederlandse stad Breda. Het bevindt zich ten noorden van het centrum van de stad. Omliggende wijken zijn Stationskwartier en Drie Hoefijzers aan de zuidkant, en aan de noordzijde Belcrum, Doornbos-Linie en Havenkwartier.\n\nHet eerste station in Breda werd geopend op 1 mei 1855, toen de Spoorlijn Roosendaal - Breda werd geopend. Dit station werd in 1863 door een nieuw gebouw vervangen, toen de lijn naar Tilburg werd geopend. Omdat Breda toen nog een vesting was en het station onder de beperkingen van de Vestingwet viel, was het zodanig uitgevoerd dat het in tijden van oorlog snel gesloopt zou kunnen worden.",
"imageUrl":"station_breda"
"description":"4815CA Breda",
"imageUrl":"NULL"
},
{
"name":"Belcrum Beach Veilingkade 12a",
"coordinates":"51.599434239284726,4.76632797992092",
"description":"Belcrum Beach is HET stadsstrand van Breda, gelegen op het Haveneiland in de wijk Belcrum. Wij zijn begonnen in 2013 op deze unieke lokatie in Breda. Een plek om te relaxen met een drankje en een hapje, genietend van de zon, gezellig kletsen met je vrienden, luisterend naar muziek van een band of DJ, soms in een festival setting. Kinderen die kunnen spelen in het zand of mee kunnen doen aan speciale kinderactiviteiten.",
"imageUrl":"belcrum_beach"
"description":"4815HC Breda",
"imageUrl":"NULL"
},
{
"name":"De Belcrum Watertoren (1935) Speelhuislaan 158",
"coordinates":"51.60135351009892,4.7705765989322755",
"description":"4815CJ Breda",
"imageUrl":"belcrum_watertoren"
"imageUrl":"NULL"
}
]

View File

@@ -1,36 +1,37 @@
[
{
"name": "Obesi Route",
"name": "rondje stad",
"locations": [
{
"name": "KesCrOkÊt breeda",
"coordinates": "2.4654645,6.2342323",
"description": "lekkere patatjes"
"name":"Prison Escape Kloosterlaan 168",
"coordinates":"51.59073795635181,4.784917104321059",
"description":"4811EE Breda",
"imageUrl":"NULL"
},
{
"name":"McDonald's Breda Karnemelkstraat",
"coordinates":"51.58596318905295,4.77586651481887",
"description":"Wist je dat McDonalds de grootste restaurantketen ter wereld is? Hierdoor hebben we een indrukwekkende geschiedenis. Maar wij kijken liever naar onze toekomst. Nieuwe restaurants, betere producten en duurzaam ondernemen. Wil je meer weten over McDonalds? Lees verder op: https://www.mcdonalds.com/nl/nl-nl/over-ons.html!"
"name":"De Koepel - FutureDome Events Nassausingel 26",
"coordinates":"51.590431588532105,4.786756741648511",
"description":"4811HP Breda",
"imageUrl":"NULL"
},
{
"name":"Escaping Breda: Escape Room Games Boschstraat 114",
"coordinates":" 51.59110835530862,4.784147222780912",
"description":"4811GK Breda",
"imageUrl":"NULL"
},
{
"name":"Wok To Go Halstraat 40",
"coordinates":"51.58650312572897,4.777467069592386",
"description":"Bij Wok To Go houden we van snelle, gezonde en smaakvolle maaltijden. Sinds 2003 ontwikkelen onze chef-koks de lekkerste wokgerechten met verse ingrediënten. We doen dit vól overgave onder het motto “Making people happy through food”. Door het roerbakken met een kleine hoeveelheid olie op grote hitte, blijven de smaak en gezonde voedingsstoffen bewaard. We kiezen voor gezonde en unieke ingrediënten en bereiden uitgebalanceerde gerechten in een Wokki box voor een gezonde levensstijl."
"name":"MEZZ Breda Keizerstraat 101",
"coordinates":"51.58394697737321,4.779757901349616",
"description":"4811HL Breda",
"imageUrl":"NULL"
},
{
"name":"De Boterhal Grote Markt 19",
"coordinates":"51.588069667604756,4.7762685632180695",
"description":"De Boterhal in Breda is een internationaal tapasrestaurant, speciaalbiercafé en wijnbar. Men kan gezellig bij ons lunchen, borrelen en dineren. Wij hebben een uitgebreide menukaart met een hele hoop bieren, wijnen, zowel per glas als per fles te verkrijgen, lunch en tapasgerechtjes. Naast het eten wat wij serveren hebben we ook een hoop bieren en wijnen. Naast de bieren op de kaart hebben wij wisselende bieren; vijf ketelbieren en vijf seizoensbieren."
},
{
"name":"Gauchos Grote Markt 33",
"coordinates":"51.58859328857082,4.77601349563689",
"description":"De middeleeuwse Grote Markt is een historische plek in het Bourgondische hart van Breda, ooit in handen van de Spaanse bezetter. Gauchos Grill-Restaurant combineert daar Brabantse gemoedelijkheid met professionele gastvrijheid. In onze Latijnse keuken bereiden wij op uw aanwijzing een malse Argentijnse steak of een smakelijk visgerecht van de grill."
},
{
"name":"The Tosti Club Breda A4, Vlaszak 2",
"coordinates":"51.58905632735254,4.780729463841719",
"description":"Je kunt bij al onze vestigingen de hele dag terecht, want bij The Tosti Club eet je het klokje rond. Dus kom gezellig ontbijten, lunchen of voor een snelle hap aan het einde van de dag (wat dacht je van onze The Tosti Slice, onze variant op pizza!). Even geen zin in brood? Dan kunnen we je ook verblijden met onder andere acaï smoothiebowls, pancakes, granolas / yoghurt of gewoon een lekkere warme drank met gebak. Mogen we je de Red Velvet fudge cake aanraden?"
"name":"Het Klooster Breda Schorsmolenstraat 13",
"coordinates":"51.58775443759389,4.765568874365066",
"description":"4811VN Breda",
"imageUrl":"NULL"
}
],
"totalDistance": 2.3434,

View File

@@ -4,17 +4,29 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import com.a1.nextlocation.R;
import com.a1.nextlocation.data.Coupon;
import com.a1.nextlocation.data.FileIO;
import com.a1.nextlocation.data.Route;
import com.a1.nextlocation.fragments.HomeFragment;
import com.a1.nextlocation.fragments.RouteFragment;
import com.a1.nextlocation.fragments.SettingsFragment;
import com.a1.nextlocation.fragments.StatisticFragment;
import com.a1.nextlocation.network.ApiHandler;
import com.a1.nextlocation.recyclerview.CouponListManager;
import com.a1.nextlocation.recyclerview.LocationListManager;
import com.a1.nextlocation.recyclerview.RouteListManager;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import java.io.File;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getName();
/**
* onCreate method that creates the main activity
* @param savedInstanceState the saved instance state of the app
@@ -27,6 +39,12 @@ public class MainActivity extends AppCompatActivity {
BottomNavigationView bottomNav = findViewById(R.id.navigation_bar);
bottomNav.setOnNavigationItemSelectedListener(navListener);
/*System.out.println(Arrays.toString(getFilesDir().listFiles()));
FileIO<Route> fileIO = new FileIO<>();
fileIO.writeFileData(new Route("TERSTSET"), getApplicationContext());
Log.d(TAG, "onCreate: " + "FILE GESCHREVENN!!!!!");*/
LocationListManager.INSTANCE.setContext(this);
LocationListManager.INSTANCE.load();
CouponListManager.INSTANCE.setContext(this);

View File

@@ -2,17 +2,26 @@ package com.a1.nextlocation.data;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.json.JSONArray;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
@@ -50,7 +59,45 @@ public class FileIO<T> {
return res;
}
public void writeFileData(T objectToWrite) {
//TODO make
}
// public void writeFileData(T objectToWrite, Context context) {
// //TODO make
// //object naar jsonobject
// //jsonarray toevoegen/maken
// //filewriter naar file
//
// String filename = "";
// if (objectToWrite instanceof Coupon){
// filename = "coupons.json";
// }
//
// if (objectToWrite instanceof Route){
// filename = "routes.json";
// }
//
// if (objectToWrite instanceof Location){
// filename = "locations.json";
// }
//
// try (FileOutputStream fileOutputStream = context.openFileOutput(filename, Context.MODE_PRIVATE)){
// String json = new Gson().toJson(objectToWrite);
//
// fileOutputStream.write(json.getBytes(StandardCharsets.UTF_8));
//
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// /*try (FileWriter fileWriter = new FileWriter(filename)){
//
// String json = new Gson().toJson(objectToWrite);
//
// fileWriter.append(json);
// fileWriter.flush();
//
// } catch (IOException e) {
// e.printStackTrace();
// }*/
// }
}

View File

@@ -35,6 +35,10 @@ public class Location implements Parcelable {
this(name,getStringFromCoordinates(latCoord,longCoord),description,imageUrl);
}
public Location(String name, android.location.Location loc, String description, String imageUrl) {
this(name,getStringFromCoordinates(loc.getLatitude(),loc.getLongitude()),description,imageUrl);
}
protected Location(Parcel in) {
name = in.readString();
coordinates = in.readString();
@@ -90,8 +94,8 @@ public class Location implements Parcelable {
public double[] getCoordinatesAsDoubles() {
double[] res = new double[2];
res[0] = getLat();
res[1] = getLong();
res[1] = getLat();
res[0] = getLong();
return res;
}
@@ -105,7 +109,45 @@ public class Location implements Parcelable {
}
public static String getStringFromCoordinates(double lat1, double long1) {
return lat1 + "," + long1;
return long1 + "," + lat1;
}
public double getDistance(Location other) {
double dlon = other.getLong() - getLong();
double dlat = other.getLat() - getLong();
double a = Math.pow(Math.sin(dlat / 2), 2)
+ Math.cos(getLat()) * Math.cos(other.getLong())
* Math.pow(Math.sin(dlon / 2),2);
double c = 2 * Math.asin(Math.sqrt(a));
// Radius of earth in kilometers. Use 3956
// for miles
double r = 6371;
// calculate the result
double distance = c * r;
return Math.floor(distance);
}
public static double getDistance(double lat1, double lon1, double lat2, double lon2) {
double dlon = lon2 - lon1;
double dlat = lat2 - lat1;
double a = Math.pow(Math.sin(dlat / 2), 2)
+ Math.cos(lat1) * Math.cos(lat2)
* Math.pow(Math.sin(dlon / 2),2);
double c = 2 * Math.asin(Math.sqrt(a));
// Radius of earth in kilometers. Use 3956
// for miles
double r = 6371;
// calculate the result
double distance = c * r;
return Math.floor(distance);
}
public GeoPoint convertToGeoPoint() {

View File

@@ -0,0 +1,69 @@
package com.a1.nextlocation.data;
import org.osmdroid.views.overlay.Polyline;
/**
* singleton to track the current route that is being followed
*/
public enum RouteHandler {
INSTANCE;
private boolean isFollowingRoute = false;
private Route currentRoute;
private int stepCount = 0;
private RouteFinishedListener routeFinishedListener;
private Polyline currentRouteLine;
public void setCurrentRouteLine(Polyline currentRouteLine) {
this.currentRouteLine = currentRouteLine;
}
public Polyline getCurrentRouteLine() {
return currentRouteLine;
}
public void setRouteFinishedListener(RouteFinishedListener routeFinishedListener) {
this.routeFinishedListener = routeFinishedListener;
}
public int getStepCount() {
return stepCount;
}
public void addStep() {
stepCount++;
}
public void finishRoute() {
stepCount = 0;
isFollowingRoute = false;
currentRoute = null;
currentRouteLine = null;
}
public void followRoute(Route route) {
this.currentRoute = route;
setFollowingRoute(true);
}
public boolean isFollowingRoute(Route route) {
return isFollowingRoute && route.equals(currentRoute);
}
public void setFollowingRoute(boolean followingRoute) {
isFollowingRoute = followingRoute;
}
public boolean isFollowingRoute() {
return isFollowingRoute;
}
public Route getCurrentRoute() {
return currentRoute;
}
@FunctionalInterface
public interface RouteFinishedListener {
void onRouteFinish();
}
}

View File

@@ -0,0 +1,39 @@
package com.a1.nextlocation.data;
import org.osmdroid.views.overlay.Polyline;
import java.util.ArrayList;
/**
* singleton to keep track of different global data
*/
public enum StaticData {
INSTANCE;
private double distanceTraveled = 0;
private int locationsVisited = 0;
private ArrayList<String> visitedNames = new ArrayList<>();
public void addDistance(double d) {
distanceTraveled += d;
}
public double getDistanceTraveled() {
return distanceTraveled;
}
public void visitLocation(Location location) {
if (!visitedNames.contains(location.getName())) {
locationsVisited++;
visitedNames.add(location.getName());
}
}
public int getLocationsVisited() {
return locationsVisited;
}
}

View File

@@ -1,11 +1,12 @@
package com.a1.nextlocation.fragments;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
@@ -13,6 +14,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -22,27 +24,41 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.a1.nextlocation.R;
import com.a1.nextlocation.recyclerview.CustomOverlay;
import com.a1.nextlocation.data.RouteHandler;
import com.a1.nextlocation.data.StaticData;
import com.a1.nextlocation.json.DirectionsResult;
import com.a1.nextlocation.network.ApiHandler;
import com.a1.nextlocation.recyclerview.LocationListManager;
import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.Overlay;
import org.osmdroid.views.overlay.OverlayItem;
import org.osmdroid.views.overlay.Polyline;
import org.osmdroid.views.overlay.compass.CompassOverlay;
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
import java.util.ArrayList;
import java.util.List;
public class HomeFragment extends Fragment {
public class HomeFragment extends Fragment implements LocationListener {
private final String userAgent = "com.ai.nextlocation.fragments";
public final static String MAPQUEST_API_KEY = "vuyXjqnAADpjeL9QwtgWGleIk95e36My";
private ImageButton imageButton;
private ImageButton stopButton;
private MapView mapView;
private final int REQUEST_PERMISSIONS_REQUEST_CODE = 1;
private final String TAG = HomeFragment.class.getCanonicalName();
// private RoadManager roadManager;
private Polyline roadOverlay;
private int color;
private Location currentLocation;
private Overlay allLocationsOverlay;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -53,6 +69,7 @@ public class HomeFragment extends Fragment {
// WRITE_EXTERNAL_STORAGE is required in order to show the map
Manifest.permission.WRITE_EXTERNAL_STORAGE);
color = requireContext().getColor(R.color.red);
}
@Override
@@ -61,15 +78,52 @@ public class HomeFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_home, container, false);
// set up the location list button
this.imageButton = view.findViewById(R.id.location_list_button);
this.imageButton.setOnClickListener(v -> {
LocationFragment locationFragment = new LocationFragment();
((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit();
});
// set up the route stop button
stopButton = view.findViewById(R.id.home_stop_route_button);
stopButton.setOnClickListener(v -> {
RouteHandler.INSTANCE.finishRoute();
stopButton.setVisibility(View.GONE);
Toast.makeText(requireContext(),getResources().getString(R.string.route_stop_toast),Toast.LENGTH_SHORT).show();
mapView.getOverlays().remove(roadOverlay);
mapView.getOverlays().remove(allLocationsOverlay);
addLocations();
mapView.invalidate();
roadOverlay = null;
});
if (RouteHandler.INSTANCE.isFollowingRoute()) {
stopButton.setVisibility(View.VISIBLE);
} else {
stopButton.setVisibility(View.GONE);
}
ApiHandler.INSTANCE.addListener(this::onDirectionsAvailable);
return view;
}
/**
* callback method that gets called when there are new directions available in the form of a {@link DirectionsResult} object.
* @param directionsResult the directions received from the api
*/
private void onDirectionsAvailable(DirectionsResult directionsResult) {
Log.d(TAG, "onDirectionsAvailable: got result! " + directionsResult);
ArrayList<GeoPoint> geoPoints = directionsResult.getGeoPoints();
roadOverlay = new Polyline();
roadOverlay.setPoints(geoPoints);
roadOverlay.setColor(color);
RouteHandler.INSTANCE.setCurrentRouteLine(roadOverlay);
Log.d(TAG, "onDirectionsAvailable: successfully added road!");
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -77,6 +131,11 @@ public class HomeFragment extends Fragment {
initMap(view);
}
/**
* This method initializes the map and all the things it needs
*
* @param view the view the map is on
*/
private void initMap(@NonNull View view) {
// set the user agent
Configuration.getInstance().setUserAgentValue(userAgent);
@@ -91,31 +150,18 @@ public class HomeFragment extends Fragment {
GpsMyLocationProvider gpsMyLocationProvider = new GpsMyLocationProvider(this.requireContext());
// add the compass overlay
CompassOverlay compassOverlay = new CompassOverlay(requireContext(),new InternalCompassOrientationProvider(requireContext()),mapView);
CompassOverlay compassOverlay = new CompassOverlay(requireContext(), new InternalCompassOrientationProvider(requireContext()), mapView);
compassOverlay.enableCompass();
mapView.getOverlays().add(compassOverlay);
addLocations();
// add the location overlay
MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(gpsMyLocationProvider, mapView);
mLocationOverlay.enableFollowLocation();
mLocationOverlay.enableMyLocation();
mapView.getOverlays().add(mLocationOverlay);
CustomOverlay customOverlay = new CustomOverlay(getResources().getDrawable(R.drawable.ic_baseline_location_on_24),mapView);
for (com.a1.nextlocation.data.Location l : LocationListManager.INSTANCE.getLocationList()) {
GeoPoint p = new GeoPoint(l.getLat(), l.getLong());
OverlayItem overlayItem = new OverlayItem(l.getName(),l.getDescription(), p);
customOverlay.addOverlayItem(overlayItem);
Log.d(TAG, "initMap: " + "succes");
}
mapView.getOverlays().add(customOverlay);
// add the zoom controller
IMapController mapController = mapView.getController();
mapController.setZoom(15.0);
@@ -125,9 +171,19 @@ public class HomeFragment extends Fragment {
try {
// request location updates for the distance checking
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
// get the current location and set it as center
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
GeoPoint startPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
mapController.setCenter(startPoint);
if (currentLocation == null) currentLocation = location;
if (location != null) {
GeoPoint start = new GeoPoint(location.getLatitude(), location.getLongitude());
mapController.setCenter(start);
}
} catch (SecurityException e) {
Log.d(TAG, "onViewCreated: exception while getting location: " + e.getLocalizedMessage());
@@ -140,7 +196,99 @@ public class HomeFragment extends Fragment {
}
displayRoute();
}
/**
* displays the route that is currently being followed as a red line
*/
private void displayRoute() {
if (RouteHandler.INSTANCE.isFollowingRoute()) {
if (roadOverlay == null) {
if (RouteHandler.INSTANCE.getCurrentRouteLine() != null) {
roadOverlay = RouteHandler.INSTANCE.getCurrentRouteLine();
mapView.getOverlays().add(roadOverlay);
mapView.invalidate();
Log.d(TAG, "initMap: successfully added road!");
}
} else {
mapView.getOverlays().add(roadOverlay);
mapView.invalidate();
Log.d(TAG, "initMap: successfully added road!");
}
}
}
/**
* adds the locations of the current route to the map. If there is no current route, show all locations
*/
private void addLocations() {
// get the locations of the current route or all locations
List<com.a1.nextlocation.data.Location> locations = RouteHandler.INSTANCE.isFollowingRoute() ? RouteHandler.INSTANCE.getCurrentRoute().getLocations() : LocationListManager.INSTANCE.getLocationList();
final ArrayList<OverlayItem> items = new ArrayList<>(locations.size());
// marker icon
Drawable marker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_baseline_location_on_24);
marker.setAlpha(255);
marker.setTint(getResources().getColor(R.color.primaryColour));
// add all locations to the overlay itemss
for (com.a1.nextlocation.data.Location location : locations) {
OverlayItem item = new OverlayItem(location.getName(), location.getDescription(), location.convertToGeoPoint());
item.setMarker(marker);
items.add(item);
}
// create the overlay that will hold all locations and add listeners
allLocationsOverlay = new ItemizedIconOverlay<OverlayItem>(items,
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
/**
* on sinlge click, navigate to that location's detail fragment
* @param index the index in the location list
* @param item the item that was clicked
* @return true
*/
@Override
public boolean onItemSingleTapUp(int index, OverlayItem item) {
com.a1.nextlocation.data.Location clicked = locations.get(index);
requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, new LocationDetailFragment(clicked)).commit();
return true;
}
/**
* on item long press, show that location's name in a toast message
* @param index the index in the location list
* @param item the item that was clicked
* @return true
*/
@Override
public boolean onItemLongPress(int index, OverlayItem item) {
com.a1.nextlocation.data.Location clicked = locations.get(index);
Toast.makeText(requireContext(), clicked.getName(), Toast.LENGTH_SHORT).show();
// create a route to the clicked location, didn't work and didn't have enough time to make it work ¯\_(ツ)_/¯
// Route route = new Route("Route to " + clicked.getName());
// route.addLocation(new com.a1.nextlocation.data.Location("Current location",currentLocation.getLatitude(),currentLocation.getLongitude(),"your location",null));
// route.addLocation(clicked);
// ApiHandler.INSTANCE.getDirections(route);
return true;
}
}, requireContext());
// add the overlay to the map
mapView.getOverlays().add(allLocationsOverlay);
Log.d(TAG, "addLocations: successfully added locations");
}
/**
* @author Ricky
* request the permissions needed for location and network, made by Ricky
* @param permissions tbe permissions we want to ask
*/
private void requestPermissionsIfNecessary(String... permissions) {
ArrayList<String> permissionsToRequest = new ArrayList<>();
if (this.getContext() != null)
@@ -158,4 +306,62 @@ public class HomeFragment extends Fragment {
REQUEST_PERMISSIONS_REQUEST_CODE);
}
}
/**
* location callback that gets called each time the location is updated. It is used for updating the distance walked and checking if there are locations you have visited
* @param location the new location
*/
@Override
public void onLocationChanged(@NonNull Location location) {
// calculate the distance walked
double distance = currentLocation.distanceTo(location); // in meters
StaticData.INSTANCE.addDistance(distance);
currentLocation = location;
//new thread because we don't want the main thread to hang, this method gets called a lot
Thread t = new Thread(() -> {
for (com.a1.nextlocation.data.Location l : LocationListManager.INSTANCE.getLocationList()) {
if (com.a1.nextlocation.data.Location.getDistance(currentLocation.getLatitude(), currentLocation.getLongitude(), l.getLat(), l.getLong()) < 10) {
StaticData.INSTANCE.visitLocation(l);
}
}
});
t.start();
}
// empty override methods for the LocationListener
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(@NonNull String provider) {
}
@Override
public void onProviderDisabled(@NonNull String provider) {
}
/**
* method that gets called when the app gets paused
*/
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
/**
* method that gets called when the app gets resumed
*/
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
}

View File

@@ -1,30 +1,33 @@
package com.a1.nextlocation.fragments;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.a1.nextlocation.R;
import com.a1.nextlocation.data.Location;
public class LocationDetailFragment extends Fragment {
private static final String TAG = LocationDetailFragment.class.getCanonicalName();
private ImageButton imageButton;
private ImageView locationImage;
private Location location;
private TextView titelText;
private TextView detailText;
public LocationDetailFragment(){}
public LocationDetailFragment() {
}
public LocationDetailFragment(Location location) {
this.location = location;
}
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -33,29 +36,17 @@ public class LocationDetailFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_location_detail, container, false);
this.titelText = view.findViewById(R.id.detail_location_name);
this.titelText.setText(location.getName());
this.detailText = view.findViewById(R.id.detail_location_text);
this.detailText.setText(location.getDescription());
this.imageButton = view.findViewById(R.id.detail_location_back_button);
this.imageButton.setOnClickListener(v -> {
LocationFragment locationFragment = new LocationFragment();
((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit();
});
this.locationImage = view.findViewById(R.id.detail_location_image);
Context context = this.locationImage.getContext();
int id = context.getResources().getIdentifier(this.location.getImageUrl(), "drawable", context.getPackageName());
this.locationImage.setImageResource(id);
if (location != null) {
Log.d(TAG, "onCreateView: the location has a name of: " + location.getName());
}
return view;
}
public void setLocation(Location location){
this.location = location;
}
}

View File

@@ -2,11 +2,14 @@ package com.a1.nextlocation.fragments;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -18,8 +21,14 @@ import com.a1.nextlocation.recyclerview.RouteAdapter;
import com.a1.nextlocation.recyclerview.RouteListManager;
import java.util.List;
import com.a1.nextlocation.data.Location;
import com.a1.nextlocation.data.Route;
import com.a1.nextlocation.json.DirectionsResult;
import com.a1.nextlocation.network.ApiHandler;
import com.a1.nextlocation.network.DirectionsListener;
public class RouteFragment extends Fragment {
private static final String TAG = RouteFragment.class.getCanonicalName();
private RecyclerView routeRecyclerView;
private RecyclerView.LayoutManager layoutManager;
@@ -63,4 +72,21 @@ public class RouteFragment extends Fragment {
this.routeRecyclerView.setAdapter(this.routeAdapter);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// ApiHandler.INSTANCE.getDirections(51.49017262451581, 4.289038164073164,51.47337383133509, 4.303535222390562);
// Route r = new Route("test");
// r.addLocation(new Location("test",51.574473766034046, 4.7628379328055175,"route",null));
// r.addLocation(new Location("test",51.577354223919876, 4.771120593941968,"route",null));
// r.addLocation(new Location("test",51.573033468635174, 4.782750651807139,"route",null));
// r.addLocation(new Location("test",51.56519104881196, 4.748246716295709,"route",null));
// r.addLocation(new Location("test",51.57367360644676, 4.74404101271347,"route",null));
// r.addLocation(new Location("test",51.57852769146427, 4.739878224473907,"route",null));
//// r.addLocation(new Location("test",51.489063681658145, 4.289596063527951,"route",null));
//// r.addLocation(new Location("test",51.483012677667766, 4.28003245468457,"route",null));
// ApiHandler.INSTANCE.getDirections(r);
}
}

View File

@@ -16,6 +16,7 @@ import android.widget.Toast;
import com.a1.nextlocation.R;
import com.a1.nextlocation.data.Coupon;
import com.a1.nextlocation.data.StaticData;
import com.a1.nextlocation.recyclerview.CouponAdapter;
import com.a1.nextlocation.recyclerview.CouponListManager;
@@ -37,6 +38,13 @@ public class StatisticFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_statistic, container, false);
TextView distance = view.findViewById(R.id.statistics_km);
TextView locs = view.findViewById(R.id.statistics_locations_visited);
double dist = StaticData.INSTANCE.getDistanceTraveled()/1000;
distance.setText("" + String.format("%.1f",dist) + " km");
locs.setText("" + StaticData.INSTANCE.getLocationsVisited());
this.couponList = CouponListManager.INSTANCE.getCouponList();
CouponAdapter adapter = new CouponAdapter(this.getContext(), this.couponList);
TextView couponNumber = view.findViewById(R.id.couponAmount);

View File

@@ -0,0 +1,190 @@
package com.a1.nextlocation.json;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import org.json.JSONArray;
import org.osmdroid.util.GeoPoint;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DirectionsResult {
private static final String TAG = DirectionsResult.class.getCanonicalName();
private List<DirectionsStep> steps = new ArrayList<>();
private double distance;
private double duration;
private double[][] wayPointCoordinates;
private GeoPoint[] startAndEndPoint = new GeoPoint[2];
public List<DirectionsStep> getSteps() {
return steps;
}
public void setSteps(List<DirectionsStep> steps) {
this.steps = steps;
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
public double getDuration() {
return duration;
}
public void setDuration(double duration) {
this.duration = duration;
}
public void addStep(DirectionsStep step) {
this.steps.add(step);
}
public GeoPoint[] getStartAndEndPoint() {
return startAndEndPoint;
}
/**
* converts all the geopoints in all the steps into an arraylist to display it on the map
* @return the list of geopoints
*/
public ArrayList<GeoPoint> getGeoPoints() {
int size = 0;
// we'll have a lot of waypoints, so calculate the size first so that the list won't have to be extended (o p t i m i z e)
for (int i = 0; i < this.getSteps().size(); i++) {
size += this.getSteps().get(i).getWaypoints().length;
}
ArrayList<GeoPoint> res = new ArrayList<>(size);
for (DirectionsStep step : this.getSteps()) {
Collections.addAll(res, step.getWaypoints());
}
return res;
}
/**
* parses a given json string into this object. It gets all the waypoints and steps and combines them so that every step also has the correct coordinates associated with it
*
* @param json the json string to parse.
*/
public void parse(String json) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonObject feature = JsonParser.parseString(json).getAsJsonObject().get("features").getAsJsonArray().get(0).getAsJsonObject();
JsonObject properties = feature.get("properties").getAsJsonObject();
JsonArray wayPointCoordinates = feature.get("geometry").getAsJsonObject().getAsJsonArray("coordinates");
this.wayPointCoordinates = new double[wayPointCoordinates.size()][2];
// fill the way point coordinates list for later use
for (int i = 0; i < wayPointCoordinates.size(); i++) {
JsonElement j = wayPointCoordinates.get(i);
JsonArray arr = j.getAsJsonArray();
this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble();
this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble();
}
JsonArray segments = properties.getAsJsonArray("segments");
for (JsonElement element : segments) {
JsonObject segment = element.getAsJsonObject();
setDistance(segment.get("distance").getAsDouble());
setDuration(segment.get("duration").getAsDouble());
JsonArray steps = segment.getAsJsonArray("steps");
for (JsonElement j : steps) {
DirectionsStep step = gson.fromJson(j, DirectionsStep.class);
double lat;
double longl;
// kinda stinky but it works
for (int i = 0; i < 2; i++) {
lat = this.wayPointCoordinates[step.getWay_points().get(i)][0];
longl = this.wayPointCoordinates[step.getWay_points().get(i)][1];
step.getWaypoints()[i] = new GeoPoint(lat, longl);
}
addStep(step);
Log.d(TAG, "parse: added step" + step);
}
}
startAndEndPoint[0] = this.getSteps().get(0).getWaypoints()[0];
startAndEndPoint[1] = this.getSteps().get(this.getSteps().size()-1).getWaypoints()[1];
}
public void parseRoute(String json) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonArray routes = JsonParser.parseString(json).getAsJsonObject().getAsJsonArray("routes");
for (JsonElement element : routes) {
JsonObject route = element.getAsJsonObject();
JsonObject summary = route.getAsJsonObject("summary");
this.distance = summary.get("distance").getAsDouble();
this.duration = summary.get("duration").getAsDouble();
JsonPrimitive geometry = route.getAsJsonPrimitive("geometry");
JsonArray wayPointCoordinates = GeometryDecoder.decodeGeometry(geometry.getAsString(), false);
this.wayPointCoordinates = new double[wayPointCoordinates.size()][2];
// fill the way point coordinates list for later use
for (int i = 0; i < wayPointCoordinates.size(); i++) {
JsonElement j = wayPointCoordinates.get(i);
JsonArray arr = j.getAsJsonArray();
this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble();
this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble();
}
JsonArray segments = route.getAsJsonArray("segments");
for (JsonElement e : segments) {
JsonObject segment = e.getAsJsonObject();
setDistance(segment.get("distance").getAsDouble());
setDuration(segment.get("duration").getAsDouble());
JsonArray steps = segment.getAsJsonArray("steps");
for (JsonElement j : steps) {
DirectionsStep step = gson.fromJson(j, DirectionsStep.class);
double lat;
double longl;
// kinda stinky but it works
for (int i = 0; i < 2; i++) {
lat = this.wayPointCoordinates[step.getWay_points().get(i)][0];
longl = this.wayPointCoordinates[step.getWay_points().get(i)][1];
step.getWaypoints()[i] = new GeoPoint(lat, longl);
}
addStep(step);
Log.d(TAG, "parse: added step" + step);
}
}
}
}
}

View File

@@ -0,0 +1,72 @@
package com.a1.nextlocation.json;
import org.osmdroid.util.GeoPoint;
import java.util.ArrayList;
/**
* pojo class that holds the step object from the api response
*/
public class DirectionsStep {
private double distance;
private double duration;
private String instruction;
private String name;
/**
* these are the actual waypoints that the step refers to. The first is the beginning of the step, and the second is what it leads to.
* The second geopoint is always the first geopoint of the next step in the list of the {@link DirectionsResult} object.
*/
private GeoPoint[] waypoints = new GeoPoint[2];
/**
* this is a list of the waypoints that are in the response, it is called way_points so it can be automatically serialized with gson
*/
private ArrayList<Integer> way_points;
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
public double getDuration() {
return duration;
}
public void setDuration(double duration) {
this.duration = duration;
}
public String getInstruction() {
return instruction;
}
public void setInstruction(String instruction) {
this.instruction = instruction;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Integer> getWay_points() {
return way_points;
}
public void setWay_points(ArrayList<Integer> way_points) {
this.way_points = way_points;
}
public GeoPoint[] getWaypoints() {
return waypoints;
}
public void setWaypoints(GeoPoint[] waypoints) {
this.waypoints = waypoints;
}
}

View File

@@ -0,0 +1,63 @@
package com.a1.nextlocation.json;
import com.google.gson.JsonArray;
import org.json.JSONArray;
import org.json.JSONException;
/**
* source: https://github.com/GIScience/openrouteservice-docs#geometry-decoding
*/
public class GeometryDecoder {
public static JsonArray decodeGeometry(String encodedGeometry, boolean inclElevation) {
JsonArray geometry = new JsonArray();
int len = encodedGeometry.length();
int index = 0;
int lat = 0;
int lng = 0;
int ele = 0;
while (index < len) {
int result = 1;
int shift = 0;
int b;
do {
b = encodedGeometry.charAt(index++) - 63 - 1;
result += b << shift;
shift += 5;
} while (b >= 0x1f);
lat += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
result = 1;
shift = 0;
do {
b = encodedGeometry.charAt(index++) - 63 - 1;
result += b << shift;
shift += 5;
} while (b >= 0x1f);
lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
if(inclElevation){
result = 1;
shift = 0;
do {
b = encodedGeometry.charAt(index++) - 63 - 1;
result += b << shift;
shift += 5;
} while (b >= 0x1f);
ele += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
}
JsonArray location = new JsonArray();
location.add(lat / 1E5);
location.add(lng / 1E5);
if(inclElevation){
location.add((float) (ele / 100));
}
geometry.add(location);
}
return geometry;
}
}

View File

@@ -4,14 +4,20 @@ import android.util.Log;
import com.a1.nextlocation.data.Location;
import com.a1.nextlocation.data.Route;
import com.a1.nextlocation.json.DirectionsResult;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public enum ApiHandler {
@@ -22,21 +28,22 @@ public enum ApiHandler {
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
private final String BASE_URL = "https://api.openrouteservice.org/v2/directions/";
private final String API_KEY = "5b3ce3597851110001cf6248d4eee2099f724255918adc71cc502b2a";
private final String DIRECTIONS_MODE = "foot_walking";
private final String DIRECTIONS_MODE = "foot-walking";
private List<DirectionsListener> listeners = new ArrayList<>();
private OkHttpClient client = new OkHttpClient();
public Route getDirections(Location startLocation, Location endLocation) {
return getDirections(startLocation.getCoordinates(),endLocation.getCoordinates());
public void getDirections(Location startLocation, Location endLocation) {
getDirections(startLocation.getCoordinates(),endLocation.getCoordinates());
}
public Route getDirections(double startLat, double startLong, double endLat, double endLong) {
return getDirections(startLat + "," + startLong, endLat + "," + endLong);
public void getDirections(double startLat, double startLong, double endLat, double endLong) {
getDirections(startLong + "," + startLat, endLong + "," + endLat);
}
public Route getDirections(String startLocation, String endLocation) {
public void getDirections(String startLocation, String endLocation) {
String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY + "&start=" +startLocation + "&end=" + endLocation;
AtomicReference<Route> res = null;
Thread t = new Thread(() -> {
Request request = new Request.Builder().url(requestUrl).build();
@@ -45,6 +52,14 @@ public enum ApiHandler {
if (response.body() != null) {
String responseString = Objects.requireNonNull(response.body()).string();
Log.d(TAG, "getDirections: got response: " + responseString);
DirectionsResult result = new DirectionsResult();
result.parse(responseString);
Log.d(TAG, "getDirections: " + result.getSteps().size());
for (DirectionsListener listener : listeners) {
listener.onDirectionsAvailable(result);
}
}
} catch (IOException e) {
@@ -54,12 +69,76 @@ public enum ApiHandler {
t.start();
// try {
// t.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
public void addListener(DirectionsListener listener) {
this.listeners.add(listener);
}
public void getDirections(Route route) {
// for (int i = 0; i < route.getLocations().size()-1; i+= 2) {
// Location start = route.getLocations().get(i);
// Location end = route.getLocations().get(i+1);
// getDirections(start,end);
// }
ArrayList<double[]> allCoords = new ArrayList<>();
for (Location location : route.getLocations()) {
allCoords.add(location.getCoordinatesAsDoubles());
}
String body = "{\"coordinates\":" + new Gson().toJson(allCoords) + "}";
String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY;
Thread t = new Thread(() -> {
RequestBody requestBody = RequestBody.create(body,JSON);
Request request = new Request.Builder()
.url(requestUrl)
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.body() != null) {
String responseString = Objects.requireNonNull(response.body()).string();
Log.d(TAG, "getDirections: got response: " + responseString);
if (responseString.startsWith("{\"error")) {
Log.e(TAG, "getDirections: ERROR IN REQUEST!");
return;
}
DirectionsResult result = new DirectionsResult();
result.parseRoute(responseString);
Log.d(TAG, "getDirections: " + result.getSteps().size());
for (DirectionsListener listener : listeners) {
listener.onDirectionsAvailable(result);
}
}
} catch (IOException e) {
Log.d(TAG, "getDirections: caught exception: " + e.getLocalizedMessage());
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return res.get();
}

View File

@@ -0,0 +1,8 @@
package com.a1.nextlocation.network;
import com.a1.nextlocation.data.Route;
import com.a1.nextlocation.json.DirectionsResult;
public interface DirectionsListener {
void onDirectionsAvailable(DirectionsResult result);
}

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M8,16h8V8H8V16zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2L12,2z"
android:fillType="evenOdd"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -27,6 +27,17 @@
android:src="@drawable/ic_baseline_outlined_flag_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/home_stop_route_button"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/location_list_button"
android:backgroundTint="@color/secondaryColour"
android:src="@drawable/ic_stop_icon"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@@ -54,6 +54,7 @@
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/statistics_km"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/km"
@@ -102,6 +103,7 @@
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/statistics_locations_visited"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/getal"

View File

@@ -10,4 +10,5 @@
<color name="primaryColour">#FF115571</color>
<color name="secondaryColour">#FF31AFB4</color>
<color name="buttonColour">#FF14212D</color>
<color name="red">#FF0000</color>
</resources>

View File

@@ -1,25 +1,21 @@
<resources>
<string name="app_name">Next Location</string>
<string name="locaties">Locaties</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="locations">Locaties</string>
<string name="routes">Routes</string>
<string name="statistieken">Statistieken</string>
<string name="instellingen">Instellingen</string>
<string name="statistics">Statistieken</string>
<string name="settings">Instellingen</string>
<string name="taal">Taal</string>
<string name="imperiaal_systeem">Imperiaal systeem</string>
<string name="_65_stand">65+ stand</string>
<string name="kleurenblind">Kleurenblind</string>
<string name="statistieken">Statistieken</string>
<string name="totale_afstand">Totale afstand:</string>
<string name="bezochte_locaties">Bezochte locaties:</string>
<string name="totale_tijd">Totale tijd:</string>
<string name="coupons_gespaard">Coupons gespaard:</string>
<string name="coupons">Coupons</string>
<string name="start_route">Start Route</string>
<string name="naam">Naam</string>
<string name="terug">Terug</string>
<string name="locatie_detail">Locatie Detail</string>
<string name="locatie_detail_tekst">Detail tekst</string>
<string name="titel">Titel</string>
<string name="km">Kilometer</string>
<string name="getal">Getal</string>
<string name="minuten">Minuten</string>
<string name="route_stop_toast">Route stopped!</string>
</resources>

View File

@@ -0,0 +1,32 @@
package com.a1.nextlocation;
import com.a1.nextlocation.data.Coupon;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class CouponTestClass {
private Coupon testCoupon;
@Before
public void init(){
testCoupon = new Coupon("TESTCODE", "REWARDISTRUE");
}
@Test
public void testSetCode() {
testCoupon.setCode("testing");
String expected = "testing";
assertEquals(expected, testCoupon.getCode());
}
@Test
public void testSetReward() {
testCoupon.setReward("testreward");
String expected = "testreward";
assertNotNull(testCoupon.getReward());
assertEquals(expected, testCoupon.getReward());
}
}

View File

@@ -0,0 +1,81 @@
package com.a1.nextlocation;
import com.a1.nextlocation.data.Coupon;
import com.a1.nextlocation.data.Data;
import com.a1.nextlocation.data.Location;
import com.a1.nextlocation.data.Route;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
public class DataTestClass {
private Data data;
@Before
public void init(){
data = new Data();
}
@Test
public void testSetDistanceTraveled() {
data.setDistanceTraveled(100);
int expected = 100;
assertEquals(expected, data.getDistanceTraveled(), 0.1);
}
@Test
public void testSetLocationsVisited() {
data.setLocationsVisited(16);
int expected = 16;
assertEquals(expected, data.getLocationsVisited());
}
@Test
public void testSetTotalTime() {
data.setTotalTime(120);
int expected = 120;
assertEquals(expected, data.getTotalTime());
}
@Test
public void testSetCouponList() {
List<Coupon> expected = new ArrayList<>();
expected.add(new Coupon("CODE1", "REWARD1"));
expected.add(new Coupon("CODE2", "REWARD2"));
expected.add(new Coupon("CODE3", "REWARD3"));
data.setCouponList(expected);
assertEquals(expected, data.getCouponList());
}
@Test
public void testNextLocation() {
Location expected = new Location("name1", "cord1", "desc1", null);
data.setNextLocation(expected);
assertEquals(expected, data.getNextLocation());
}
@Test
public void testLastLocation() {
Location expected = new Location("name2", "cord2", "desc2", null);
data.setLastLocation(expected);
assertEquals(expected, data.getLastLocation());
}
@Test
public void testCurrentRoute() {
Route expected = new Route("testRoute1");
data.setCurrentRoute(expected);
assertEquals(expected, data.getCurrentRoute());
}
}

View File

@@ -0,0 +1,57 @@
package com.a1.nextlocation;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.InstrumentationInfo;
import android.widget.ArrayAdapter;
import com.a1.nextlocation.data.FileIO;
import com.a1.nextlocation.data.Location;
import com.a1.nextlocation.data.Route;
import com.google.gson.reflect.TypeToken;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
public class FileIOTest {
// @Test
// public void testReadFileIO() {
// //System.out.println(Arrays.toString(mMockContext.fileList()));
// Context mMockContext = mock(MainActivity.class);
// List<Route> expected = new ArrayList<>();
// Route testRoute = new Route("rondje stad");
// testRoute.addLocation(new Location("kees kroket", "2.4654645,6.2342323", "lekkere patatjes", null));
// testRoute.setTotalDistance(2.3434f);
// testRoute.setTotalTime(342342);
// expected.add(testRoute);
//
// /*
// FileIO<ArrayList<Route>> fileIO = new FileIO<>();
// ArrayList<Route> res = fileIO.readFileData(context, "routes.json",new TypeToken<ArrayList<Route>>(){}.getType());
// */
//
// if (mMockContext.getAssets() == null)
// System.out.println("daar ga je");
//
// FileIO<ArrayList<Route>> fileIO = new FileIO<>();
// ArrayList<Route> res = fileIO.readFileData(mMockContext, "routes.json", new TypeToken<ArrayList<Route>>(){}.getType());
//
// assertEquals(expected, res);
//
// }
}

View File

@@ -0,0 +1,97 @@
package com.a1.nextlocation;
import com.a1.nextlocation.data.Location;
import org.junit.Before;
import org.junit.Test;
import org.osmdroid.util.GeoPoint;
import static org.junit.Assert.*;
public class LocationTest {
private Location testLocation;
@Before
public void init(){
testLocation = new Location("testName", "15.4,27.5", "testDesc", null);
}
@Test
public void nameTest(){
String testName = "nameTestName";
String expectedBefore = "testName";
String expectedAfter = "nameTestName";
assertEquals(expectedBefore, testLocation.getName());
testLocation.setName(testName);
assertEquals(expectedAfter, testLocation.getName());
}
@Test
public void coordinatesTest(){
String testCoordinaates = "32.4,15.7";
String expectedBefore = "15.4,27.5";
String expectedAfter = "32.4,15.7";
assertEquals(expectedBefore, testLocation.getCoordinates());
testLocation.setCoordinates(testCoordinaates);
assertEquals(expectedAfter, testLocation.getCoordinates());
}
@Test
public void descriptionTest(){
String testDescription = "This description is a test!";
String expectedBefore = "testDesc";
String expectedAfter = "This description is a test!";
assertEquals(expectedBefore, testLocation.getDescription());
testLocation.setDescription(testDescription);
assertEquals(expectedAfter, testLocation.getDescription());
}
@Test
public void ImageURLTest(){
String testURL = "https://i.imgur.com/FvohwaS.png";
String expectedBefore = null;
String expectedAfter = "https://i.imgur.com/FvohwaS.png";
assertEquals(expectedBefore ,testLocation.getImageUrl());
testLocation.setImageUrl(testURL);
assertEquals(expectedAfter, testLocation.getImageUrl());
}
@Test
public void coordinateDoublesTest(){
double[] testDoubles = new double[2];
testDoubles[0] = 15.4;
testDoubles[1] = 27.5;
double [] expectedCoordAsDouble = testDoubles;
String expectedStringFromDouble = "15.4,27.5";
assertArrayEquals(expectedCoordAsDouble, testLocation.getCoordinatesAsDoubles(), 0.1);
assertEquals(expectedStringFromDouble, testLocation.getStringFromCoordinates(testDoubles[0], testDoubles[1]));
}
@Test
public void geoPointTest(){
String testGeoPointCoords = "30.3,55.5";
GeoPoint expectedBefore = new GeoPoint(15.4, 27.5);
GeoPoint expectedAfter = new GeoPoint(30.3, 55.5);
assertEquals(expectedBefore, testLocation.convertToGeoPoint());
testLocation.setCoordinates(testGeoPointCoords);
assertEquals(expectedAfter, testLocation.convertToGeoPoint());
}
@Test
public void AlternateConstructorTest(){
Location alternateTestLocation = new Location("testName", 15.4, 27.5, "testDesc", null);
assertNotNull(alternateTestLocation);
}
}

View File

@@ -0,0 +1,93 @@
package com.a1.nextlocation;
import com.a1.nextlocation.data.Location;
import com.a1.nextlocation.data.Route;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class RouteTest {
private Route route;
@Before
public void init(){
route = new Route("testName");
}
@Test
public void nameTest(){
String testName = "secondTestName";
String expectedBefore = "testName";
String expectedAfter = "secondTestName";
assertEquals(expectedBefore, route.getName());
route.setName(testName);
assertEquals(expectedAfter, route.getName());
}
@Test
public void getLocationsTest(){
List<Location> expected = new ArrayList<>();
assertEquals(expected, route.getLocations());
}
@Test
public void SetLocationsTest(){
List<Location> testList = new ArrayList<>();
testList.add(new Location("name1", "coord1", "desc1", null));
testList.add(new Location("name2", "coord2", "desc2", null));
testList.add(new Location("name3", "coord3", "desc3", null));
List<Location> expectedBefore = new ArrayList<>();
List<Location> expectedAfter = testList;
assertEquals(expectedBefore, route.getLocations());
route.setLocations(testList);
assertEquals(expectedAfter, route.getLocations());
}
@Test
public void AddLocationTest(){
Location testLocation = new Location("testLocationName", "testCoordinates", "testDescription", null);
List<Location> expectedBefore = new ArrayList<>();
List<Location> expectedAfter = new ArrayList<>();
expectedAfter.add(testLocation);
assertEquals(expectedBefore, route.getLocations());
route.addLocation(testLocation);
assertEquals(expectedAfter, route.getLocations());
}
@Test
public void totalDistanceTest(){
float testDistance = 523;
float expectedBefore = 0;
float expectedAfter = 523;
assertEquals(expectedBefore, route.getTotalDistance(), 0.01);
route.setTotalDistance(testDistance);
assertEquals(expectedAfter, route.getTotalDistance(), 0.01);
}
@Test
public void totalTimeTest(){
int testTime = 36;
int expectedBefore = 0;
int expectedAfter = 36;
assertEquals(expectedBefore, route.getTotalTime());
route.setTotalTime(testTime);
assertEquals(expectedAfter, route.getTotalTime());
}
}