diff --git a/app/src/main/assets/locations.json b/app/src/main/assets/locations.json index 1bbddb1..c754cd3 100644 --- a/app/src/main/assets/locations.json +++ b/app/src/main/assets/locations.json @@ -82,7 +82,7 @@ "name":"MEZZ Breda Keizerstraat 101", "coordinates":"51.58394697737321,4.779757901349616", "description":"4811HL Breda", - "imageUrl":"NULL" + "imageUrl":"mezz_breda" }, { "name":"Het Klooster Breda Schorsmolenstraat 13", diff --git a/app/src/main/assets/routes.json b/app/src/main/assets/routes.json index 46c734f..ccfba28 100644 --- a/app/src/main/assets/routes.json +++ b/app/src/main/assets/routes.json @@ -3,9 +3,35 @@ "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":"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":"MEZZ Breda Keizerstraat 101", + "coordinates":"51.58394697737321,4.779757901349616", + "description":"4811HL Breda", + "imageUrl":"NULL" + }, + { + "name":"Het Klooster Breda Schorsmolenstraat 13", + "coordinates":"51.58775443759389,4.765568874365066", + "description":"4811VN Breda", + "imageUrl":"NULL" } ], "totalDistance": 2.3434, diff --git a/app/src/main/java/com/a1/nextlocation/MainActivity.java b/app/src/main/java/com/a1/nextlocation/MainActivity.java index a615490..ef12e7d 100644 --- a/app/src/main/java/com/a1/nextlocation/MainActivity.java +++ b/app/src/main/java/com/a1/nextlocation/MainActivity.java @@ -3,6 +3,9 @@ package com.a1.nextlocation; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; @@ -23,6 +26,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import java.io.File; import java.util.Arrays; +import java.util.Locale; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getName(); @@ -52,9 +56,33 @@ public class MainActivity extends AppCompatActivity { RouteListManager.INSTANCE.setContext(this); RouteListManager.INSTANCE.load(); + // initialize saved language from sharedPreferences + setLocale(loadLocale()); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, new HomeFragment()).commit(); } + /** + * loads the saved language from SharedPreferences + * @return the language as string + */ + private String loadLocale(){ + SharedPreferences sharedPreferences = getSharedPreferences("Settings", Activity.MODE_PRIVATE); + return sharedPreferences.getString("Language", "nl"); + } + + /** + * sets the language of the application to the desired one + * @param language the desired language + */ + private void setLocale(String language){ + Locale locale = new Locale(language); + Locale.setDefault(locale); + Configuration configuration = new Configuration(); + configuration.setLocale(locale); + getBaseContext().getResources().updateConfiguration(configuration, getBaseContext().getResources().getDisplayMetrics()); + } + private BottomNavigationView.OnNavigationItemSelectedListener navListener = item -> { Fragment selectedFragment = null; diff --git a/app/src/main/java/com/a1/nextlocation/data/Location.java b/app/src/main/java/com/a1/nextlocation/data/Location.java index f7d2362..ed4ccc8 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Location.java +++ b/app/src/main/java/com/a1/nextlocation/data/Location.java @@ -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() { diff --git a/app/src/main/java/com/a1/nextlocation/data/StaticData.java b/app/src/main/java/com/a1/nextlocation/data/StaticData.java new file mode 100644 index 0000000..0f0d4e3 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/StaticData.java @@ -0,0 +1,47 @@ +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 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; + } + + private Polyline currentRoute; + + public void setCurrentRoute(Polyline currentRoute) { + this.currentRoute = currentRoute; + } + + public Polyline getCurrentRoute() { + return currentRoute; + } + +} diff --git a/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java index 984e38c..4279c89 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java @@ -61,22 +61,18 @@ public class CouponFragment extends Fragment { private void showPopup(Coupon coupon) { AlertDialog.Builder activateBuilder = new AlertDialog.Builder(getContext()); AlertDialog.Builder couponCodeBuilder = new AlertDialog.Builder(getContext()); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setMessage("Weet je zeker dat je deze coupon wilt activeren?"); + activateBuilder.setMessage(getResources().getString(R.string.activate_question)); activateBuilder.setCancelable(true); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setPositiveButton("activeren", (dialog, which) -> { - // TODO: use string resources instead of hardcoded strings + activateBuilder.setPositiveButton(R.string.activate, (dialog, which) -> { dialog.cancel(); couponCodeBuilder.setMessage("Code: " + coupon.getCode()); - couponCodeBuilder.setPositiveButton("Klaar", (dialog1, which1) -> { + couponCodeBuilder.setPositiveButton(R.string.done, (dialog1, which1) -> { dialog.cancel(); }); AlertDialog couponCodePopup = couponCodeBuilder.create(); couponCodePopup.show(); }); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setNegativeButton("annuleren", (dialog, which) -> dialog.cancel()); + activateBuilder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.cancel()); AlertDialog couponPopup = activateBuilder.create(); couponPopup.show(); diff --git a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java index 237d7ca..1786782 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java @@ -5,7 +5,9 @@ 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 +15,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 +25,38 @@ 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.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 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; @Override public void onCreate(Bundle savedInstanceState) { @@ -52,7 +66,10 @@ public class HomeFragment extends Fragment { Manifest.permission.ACCESS_FINE_LOCATION, // WRITE_EXTERNAL_STORAGE is required in order to show the map Manifest.permission.WRITE_EXTERNAL_STORAGE); +// roadManager = new MapQuestRoadManager(MAPQUEST_API_KEY); +// roadManager.addRequestOption("routeType=foot-walking"); + color = requireContext().getColor(R.color.red); } @Override @@ -67,9 +84,30 @@ public class HomeFragment extends Fragment { ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit(); }); + ApiHandler.INSTANCE.addListener(this::onDirectionsAvailable); return view; } + private void onDirectionsAvailable(DirectionsResult directionsResult) { + Log.d(TAG, "onDirectionsAvailable: got result! " + directionsResult); + ArrayList geoPoints = directionsResult.getGeoPoints(); + roadOverlay = new Polyline(); + roadOverlay.setPoints(geoPoints); + + // this is for mapquest, but it gives a "no value for guidancelinkcollection" error and google has never heard of that +// GeoPoint[] gp = directionsResult.getStartAndEndPoint(); +// ArrayList arrayList = new ArrayList<>(Arrays.asList(gp)); +// Road road = roadManager.getRoad(arrayList); +// roadOverlay = RoadManager.buildRoadOverlay(road); + + roadOverlay.setColor(color); + + + StaticData.INSTANCE.setCurrentRoute(roadOverlay); + Log.d(TAG, "onDirectionsAvailable: successfully added road!"); + + } + @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -77,6 +115,10 @@ 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); @@ -95,25 +137,14 @@ public class HomeFragment extends Fragment { 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); @@ -122,10 +153,22 @@ public class HomeFragment extends Fragment { LocationManager locationManager = (LocationManager) requireActivity().getSystemService(Context.LOCATION_SERVICE); + + try { + + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,this); + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0,this); + 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()); @@ -138,7 +181,64 @@ public class HomeFragment extends Fragment { } + + displayRoute(); + } + + private void displayRoute() { + + if (roadOverlay == null) { + if (StaticData.INSTANCE.getCurrentRoute() != null) { + roadOverlay = StaticData.INSTANCE.getCurrentRoute(); + 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!"); + } + } + + private void addLocations() { + List locations = LocationListManager.INSTANCE.getLocationList(); + final ArrayList items = new ArrayList<>(locations.size()); + Drawable marker = ContextCompat.getDrawable(requireContext(),R.drawable.ic_baseline_location_on_24); + marker.setAlpha(255); + marker.setTint(getResources().getColor(R.color.primaryColour)); + for (com.a1.nextlocation.data.Location location : locations) { + OverlayItem item = new OverlayItem(location.getName(),location.getDescription(),location.convertToGeoPoint()); + item.setMarker(marker); + items.add(item); + } + Overlay allLocationsOverlay = new ItemizedIconOverlay(items, + new ItemizedIconOverlay.OnItemGestureListener() { + @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 false; + } + + @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(); +// 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()); + + mapView.getOverlays().add(allLocationsOverlay); + Log.d(TAG, "addLocations: successfully added locations"); + + } + private void requestPermissionsIfNecessary(String... permissions) { ArrayList permissionsToRequest = new ArrayList<>(); if (this.getContext() != null) @@ -156,4 +256,37 @@ public class HomeFragment extends Fragment { REQUEST_PERMISSIONS_REQUEST_CODE); } } + + @Override + public void onLocationChanged(@NonNull Location location) { + 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 + 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(); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + + } + + @Override + public void onProviderEnabled(@NonNull String provider) { + + } + + @Override + public void onProviderDisabled(@NonNull String provider) { + + } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java index 82bcabb..19f73cd 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java @@ -1,20 +1,33 @@ package com.a1.nextlocation.fragments; +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 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 Location location; + + public LocationDetailFragment() { + + } + + public LocationDetailFragment(Location location) { + this.location = location; + } @Override public void onCreate(Bundle savedInstanceState) { @@ -31,6 +44,9 @@ public class LocationDetailFragment extends Fragment { ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit(); }); + if (location != null) { + Log.d(TAG, "onCreateView: the location has a name of: " + location.getName()); + } return view; } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java index 30a4caa..87eb2b1 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java @@ -9,10 +9,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; +import android.widget.Button; import android.widget.TextView; +import android.widget.Toast; import com.a1.nextlocation.R; import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.network.ApiHandler; public class RouteDetailFragment extends Fragment { @@ -35,6 +38,8 @@ public class RouteDetailFragment extends Fragment { this.routeDetailText = view.findViewById(R.id.routeDetailText); this.routeDetailText.setText(this.route.getName()); + Button startButton = view.findViewById(R.id.start_route_button); + startButton.setOnClickListener(this::startRoute); this.imageButton = view.findViewById(R.id.route_detail_back_button); this.imageButton.setOnClickListener(v -> { @@ -45,4 +50,11 @@ public class RouteDetailFragment extends Fragment { return view; } + + public void startRoute(View view) { + ApiHandler.INSTANCE.getDirections(route); + Toast.makeText(requireContext(),"Route started!",Toast.LENGTH_SHORT).show(); + ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, new HomeFragment()).addToBackStack(null).commit(); + + } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java index e9e6f85..2369e6d 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java @@ -39,7 +39,6 @@ public class RouteFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ApiHandler.INSTANCE.addListener(this::onDirectionsAvailable); } @@ -78,16 +77,16 @@ public class RouteFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); -// ApiHandler.INSTANCE.getDirections(8.681436,49.41461,8.687872,49.420318); +// ApiHandler.INSTANCE.getDirections(51.49017262451581, 4.289038164073164,51.47337383133509, 4.303535222390562); // Route r = new Route("test"); -// r.addLocation(new Location("test",8.681436,49.41461,"route",null)); -// r.addLocation(new Location("test",8.687872,49.420318,"route",null)); +// 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); } - - public void onDirectionsAvailable(DirectionsResult result) { - Log.d(TAG, "onDirectionsAvailable: got result! " + result); - - - } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java index 232afa9..6838387 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java @@ -1,15 +1,20 @@ package com.a1.nextlocation.fragments; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Spinner; @@ -17,28 +22,27 @@ import android.widget.Spinner; import com.a1.nextlocation.MainActivity; import com.a1.nextlocation.R; +import java.util.Locale; + public class SettingsFragment extends Fragment { + private SharedPreferences.Editor editor; + private ImageView imageButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + editor = getContext().getSharedPreferences("Settings", Context.MODE_PRIVATE).edit(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - return inflater.inflate(R.layout.fragment_settings, container, false); - } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); + View view = inflater.inflate(R.layout.fragment_settings, container, false); - // Inflate the layout for this fragment - Spinner dropdown = view.findViewById(R.id.dropdown_menu_Settings); + initializeLanguageDropdown(view); this.imageButton = view.findViewById(R.id.settings_back_button); this.imageButton.setOnClickListener(v -> { @@ -46,9 +50,95 @@ public class SettingsFragment extends Fragment { ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, homeFragment).addToBackStack(null).commit(); }); + return view; + } + + private void initializeLanguageDropdown(View view) { + Spinner languageDropdown = view.findViewById(R.id.dropdown_menu_Settings); String[] items = new String[]{"Nederlands", "Engels", "Chinees"}; ArrayAdapter arrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_dropdown_item, items); + languageDropdown.setAdapter(arrayAdapter); - dropdown.setAdapter(arrayAdapter); + // set the language dropdown on the currently selected language stored in the sharedPreferences + languageDropdown.setSelection(languageToDropdownPosition(getContext().getSharedPreferences("Settings", Context.MODE_PRIVATE).getString("Language", ""))); + + long previousID = languageDropdown.getSelectedItemId(); + languageDropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + setLocale(dropdownPositionToLanguage(id)); + if (id != previousID) { + Fragment currentFragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_layout); + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.detach(currentFragment); + fragmentTransaction.attach(currentFragment); + fragmentTransaction.commit(); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + } + + /** + * converts the languageDropdown position to the belonging language + * + * @param id desired position to convert + * @return the language belonging to the position of the languageDropdown + */ + private String dropdownPositionToLanguage(long id) { + switch ((int) id) { + case 0: + return "nl"; + case 1: + return "en"; + default: + return ""; + } + } + + /** + * converts language to the languageDropdown position + * + * @param language desired language to convert + * @return the position of the language in the languageDropdown + */ + private int languageToDropdownPosition(String language) { + switch (language) { + case "nl": + return 0; + case "en": + return 1; + default: + return 1; + } + } + + /** + * reloads the fragment + */ + private void refresh() { + Fragment currentFragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_layout); + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.detach(currentFragment); + fragmentTransaction.attach(currentFragment); + fragmentTransaction.commit(); + } + + /** + * changes the current language to the desired language and saves this setting in SharedPreferences + * + * @param language the desired language to translate to + */ + private void setLocale(String language) { + Locale locale = new Locale(language); + Locale.setDefault(locale); + Configuration config = new Configuration(); + config.setLocale(locale); + getContext().getResources().updateConfiguration(config, getContext().getResources().getDisplayMetrics()); + editor.putString("Language", language); + editor.apply(); } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java index a4080c5..83e3a07 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java @@ -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; @@ -36,6 +37,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); diff --git a/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java b/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java index 8cf1c7c..7f52783 100644 --- a/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java +++ b/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java @@ -15,6 +15,7 @@ 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 { @@ -23,6 +24,7 @@ public class DirectionsResult { private double distance; private double duration; private double[][] wayPointCoordinates; + private GeoPoint[] startAndEndPoint = new GeoPoint[2]; public List getSteps() { return steps; @@ -52,8 +54,31 @@ public class DirectionsResult { 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 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 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) { @@ -86,7 +111,7 @@ public class DirectionsResult { for (JsonElement j : steps) { - DirectionsStep step = gson.fromJson(j,DirectionsStep.class); + DirectionsStep step = gson.fromJson(j, DirectionsStep.class); double lat; double longl; @@ -94,7 +119,7 @@ public class DirectionsResult { 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); + step.getWaypoints()[i] = new GeoPoint(lat, longl); } addStep(step); @@ -102,6 +127,9 @@ public class DirectionsResult { } } + startAndEndPoint[0] = this.getSteps().get(0).getWaypoints()[0]; + startAndEndPoint[1] = this.getSteps().get(this.getSteps().size()-1).getWaypoints()[1]; + } public void parseRoute(String json) { @@ -115,7 +143,7 @@ public class DirectionsResult { this.duration = summary.get("duration").getAsDouble(); JsonPrimitive geometry = route.getAsJsonPrimitive("geometry"); - JsonArray wayPointCoordinates = GeometryDecoder.decodeGeometry(geometry.getAsString(),false); + JsonArray wayPointCoordinates = GeometryDecoder.decodeGeometry(geometry.getAsString(), false); this.wayPointCoordinates = new double[wayPointCoordinates.size()][2]; @@ -140,7 +168,7 @@ public class DirectionsResult { for (JsonElement j : steps) { - DirectionsStep step = gson.fromJson(j,DirectionsStep.class); + DirectionsStep step = gson.fromJson(j, DirectionsStep.class); double lat; double longl; @@ -148,7 +176,7 @@ public class DirectionsResult { 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); + step.getWaypoints()[i] = new GeoPoint(lat, longl); } addStep(step); @@ -158,7 +186,5 @@ public class DirectionsResult { } - - } } diff --git a/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java b/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java index 1b480a8..570e683 100644 --- a/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java +++ b/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java @@ -38,7 +38,7 @@ public enum ApiHandler { } public void getDirections(double startLat, double startLong, double endLat, double endLong) { - getDirections(startLat + "," + startLong, endLat + "," + endLong); + getDirections(startLong + "," + startLat, endLong + "," + endLat); } public void getDirections(String startLocation, String endLocation) { @@ -69,6 +69,12 @@ public enum ApiHandler { t.start(); +// try { +// t.join(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + } public void addListener(DirectionsListener listener) { @@ -104,6 +110,10 @@ public enum ApiHandler { 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); @@ -121,6 +131,12 @@ public enum ApiHandler { t.start(); + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 5510e08..751fdc9 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -47,7 +47,7 @@ + + + Next Location + Locaties + Routes + Statistieken + Instellingen + Taal + Imperiaal systeem + 65+ stand + Kleurenblind + Totale afstand: + Bezochte locaties: + Totale tijd: + Coupons gespaard: + Coupons + Start Route + Weet je zeker dat je deze coupon wilt activeren? + activeren + Klaar + annuleren + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index cf6f6b1..a8f6080 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,4 +10,5 @@ #FF115571 #FF31AFB4 #FF14212D + #FF0000 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bfbd17f..1cfcd8d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,25 +1,21 @@ - Next Location - Locaties + Next Location + Location Routes - Statistieken - Instellingen - Taal - Imperiaal systeem - 65+ stand - Kleurenblind - Totale afstand: - Bezochte locaties: - Totale tijd: - Coupons gespaard: + Statistics + Settings + Language + Imperial system + 65+ mode + Colorblind + Total distance: + Visited locations: + Total time: + Coupons collected: Coupons Start Route - Naam - Terug - Locatie Detail - Detail tekst - Titel - Kilometer - Getal - Minuten + Are you sure you want to activate this coupon? + activate + Done + cancel \ No newline at end of file