diff --git a/app/build.gradle b/app/build.gradle index 8eb7ba2..1115b64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,12 @@ android { dependencies { + def room_version = "2.2.5" + + implementation "androidx.room:room-runtime:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + + implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 465afef..f5def4b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + diff --git a/app/src/main/java/com/a1/nextlocation/data/Coupon.java b/app/src/main/java/com/a1/nextlocation/data/Coupon.java index b980ab3..14456a5 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Coupon.java +++ b/app/src/main/java/com/a1/nextlocation/data/Coupon.java @@ -1,4 +1,48 @@ package com.a1.nextlocation.data; +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import org.jetbrains.annotations.NotNull; + +@Entity(tableName = "coupon") public class Coupon { + + /** + * fields need to be public for the database to be able to use them + */ + @PrimaryKey + @NonNull + @ColumnInfo(name = "code") + private String code; + + @ColumnInfo(name = "reward") + @NonNull + private String reward; + + + public Coupon(@NonNull String code, @NotNull String reward) { + this.code = code; + this.reward = reward; + } + + @NonNull + public String getCode() { + return code; + } + + @NonNull + public String getReward() { + return reward; + } + + public void setCode(@NonNull String code) { + this.code = code; + } + + public void setReward(@NonNull String reward) { + this.reward = reward; + } } diff --git a/app/src/main/java/com/a1/nextlocation/data/Data.java b/app/src/main/java/com/a1/nextlocation/data/Data.java index 8e09c97..7f4b5eb 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Data.java +++ b/app/src/main/java/com/a1/nextlocation/data/Data.java @@ -1,4 +1,95 @@ package com.a1.nextlocation.data; +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.PrimaryKey; + +import java.util.List; + +@Entity public class Data { + + + + @PrimaryKey + @NonNull + private float distanceTraveled; + + private int locationsVisited; + private int totalTime; + private List couponList; + + @Ignore + private Location nextLocation; + + @Ignore + private Location lastLocation; + + @Ignore + private Route currentRoute; + + + public Data() { + this.distanceTraveled = 0; + this.locationsVisited = 0; + this.totalTime = 0; + } + + + public float getDistanceTraveled() { + return distanceTraveled; + } + + public void setDistanceTraveled(float distanceTraveled) { + this.distanceTraveled = distanceTraveled; + } + + public int getLocationsVisited() { + return locationsVisited; + } + + public void setLocationsVisited(int locationsVisited) { + this.locationsVisited = locationsVisited; + } + + public int getTotalTime() { + return totalTime; + } + + public void setTotalTime(int totalTime) { + this.totalTime = totalTime; + } + + public List getCouponList() { + return couponList; + } + + public void setCouponList(List couponList) { + this.couponList = couponList; + } + + public Location getNextLocation() { + return nextLocation; + } + + public void setNextLocation(Location nextLocation) { + this.nextLocation = nextLocation; + } + + public Location getLastLocation() { + return lastLocation; + } + + public void setLastLocation(Location lastLocation) { + this.lastLocation = lastLocation; + } + + public Route getCurrentRoute() { + return currentRoute; + } + + public void setCurrentRoute(Route currentRoute) { + this.currentRoute = currentRoute; + } } diff --git a/app/src/main/java/com/a1/nextlocation/data/FileIO.java b/app/src/main/java/com/a1/nextlocation/data/FileIO.java index 71c08f6..6d6d8f9 100644 --- a/app/src/main/java/com/a1/nextlocation/data/FileIO.java +++ b/app/src/main/java/com/a1/nextlocation/data/FileIO.java @@ -1,4 +1,12 @@ package com.a1.nextlocation.data; public class FileIO { + + public static void readFileData() { + + } + + public static void writeFileData() { + + } } 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 2375e04..5f839ad 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Location.java +++ b/app/src/main/java/com/a1/nextlocation/data/Location.java @@ -1,4 +1,49 @@ package com.a1.nextlocation.data; +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import org.jetbrains.annotations.NotNull; + +@Entity(tableName = "location") public class Location { + + @PrimaryKey + @NonNull + private String name; + + private String coordinates; + private String description; + + public Location(@NotNull String name, String coordinates, String description) { + this.name = name; + this.coordinates = coordinates; + this.description = description; + } + + @NotNull + public String getName() { + return name; + } + + public void setName(@NotNull String name) { + this.name = name; + } + + public String getCoordinates() { + return coordinates; + } + + public void setCoordinates(String coordinates) { + this.coordinates = coordinates; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } } diff --git a/app/src/main/java/com/a1/nextlocation/data/Route.java b/app/src/main/java/com/a1/nextlocation/data/Route.java index 213f3ba..c1d1bf0 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Route.java +++ b/app/src/main/java/com/a1/nextlocation/data/Route.java @@ -1,4 +1,75 @@ package com.a1.nextlocation.data; +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +@Entity(tableName = "route") public class Route { + + @PrimaryKey + @NonNull + private String name; + + private List locations; + + @ColumnInfo(name = "total_distance") + private float totalDistance; + + @ColumnInfo(name = "total_time") + private int totalTime; + + public Route(@NotNull String name) { + + this.name = name; + this.locations = new ArrayList<>(); + + } + + public void addLocation(Location location) { + this.locations.add(location); + } + + @NotNull + public String getName() { + return name; + } + + public void setName(@NotNull String name) { + this.name = name; + } + + public List getLocations() { + return locations; + } + + public void setLocations(List locations) { + this.locations = locations; + } + + public float getTotalDistance() { + //TODO calculate total distance according to all locations in list + return totalDistance; + } + + + public int getTotalTime() { + //TODO calculate total time according to all locations in list + return totalTime; + } + + public void setTotalDistance(float totalDistance) { + this.totalDistance = totalDistance; + } + + public void setTotalTime(int totalTime) { + this.totalTime = totalTime; + } + } diff --git a/app/src/main/java/com/a1/nextlocation/data/db/Database.java b/app/src/main/java/com/a1/nextlocation/data/db/Database.java new file mode 100644 index 0000000..7ab918c --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/Database.java @@ -0,0 +1,58 @@ +package com.a1.nextlocation.data.db; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.sqlite.db.SupportSQLiteDatabase; + +import com.a1.nextlocation.data.Coupon; +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.data.db.dao.CouponDao; +import com.a1.nextlocation.data.db.dao.LocationDao; +import com.a1.nextlocation.data.db.dao.RouteDao; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @author Sem + */ +@androidx.room.Database(entities = {Coupon.class,Route.class, Location.class},version = 1,exportSchema = false) +public abstract class Database extends RoomDatabase { + + public abstract RouteDao routeDao(); + public abstract CouponDao couponDao(); + public abstract LocationDao locationDao(); + + private static volatile Database INSTANCE; + private static final int NUMBER_OF_THREADS = 4; + static final ExecutorService databaseWriterExecutor = Executors.newFixedThreadPool(NUMBER_OF_THREADS); + + public static Database getDatabase(final Context context) { + if (INSTANCE == null){ + synchronized (Database.class) { + if (INSTANCE == null) { + + INSTANCE = Room.databaseBuilder(context.getApplicationContext(), + Database.class,"next_location_db").addCallback(callback).build(); + } + } + } + return INSTANCE; + } + + private static RoomDatabase.Callback callback = new RoomDatabase.Callback() { + @Override + public void onCreate(@NonNull SupportSQLiteDatabase db) { + super.onCreate(db); + + databaseWriterExecutor.execute(() -> { + // TODO populate our database here + }); + + } + }; +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/dao/CouponDao.java b/app/src/main/java/com/a1/nextlocation/data/db/dao/CouponDao.java new file mode 100644 index 0000000..ca68438 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/dao/CouponDao.java @@ -0,0 +1,31 @@ +package com.a1.nextlocation.data.db.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import androidx.room.Update; + +import com.a1.nextlocation.data.Coupon; + +import java.util.List; + +@Dao +public interface CouponDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertAll(Coupon... coupons); + + @Query("DELETE FROM coupon") + void deleteAll(); + + @Query("SELECT * FROM coupon") + LiveData> selectAll(); + + /* + to add an observer to the livedata, you can use the example from https://medium.com/mindorks/using-room-database-with-livedata-android-jetpack-cbf89b677b47 + */ + + @Query("SELECT * FROM coupon WHERE code = :code LIMIT 1") + Coupon selectCouponByCode(String code); +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/dao/LocationDao.java b/app/src/main/java/com/a1/nextlocation/data/db/dao/LocationDao.java new file mode 100644 index 0000000..c0da25c --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/dao/LocationDao.java @@ -0,0 +1,27 @@ +package com.a1.nextlocation.data.db.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +import com.a1.nextlocation.data.Location; + +import java.util.List; + +@Dao +public interface LocationDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertAll(Location... locations); + + @Query("DELETE FROM location") + void deleteAll(); + + @Query("SELECT * FROM location") + LiveData> selectAll(); + + @Query("SELECT * FROM location WHERE name = :name LIMIT 1") + Location getLocationByName(String name); + +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/dao/RouteDao.java b/app/src/main/java/com/a1/nextlocation/data/db/dao/RouteDao.java new file mode 100644 index 0000000..4d30dc6 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/dao/RouteDao.java @@ -0,0 +1,27 @@ +package com.a1.nextlocation.data.db.dao; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Update; + +import com.a1.nextlocation.data.Route; + +import java.util.List; + +@Dao +public interface RouteDao { + + @Insert + void insertAll(Route... routes); + + @Query("DELETE FROM route") + void deleteAll(); + + @Query("SELECT * FROM route") + LiveData> getAll(); + + @Query("SELECT * FROM route where name = :name LIMIT 1") + Route getRouteByName(String name); +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/repositories/CouponRepository.java b/app/src/main/java/com/a1/nextlocation/data/db/repositories/CouponRepository.java new file mode 100644 index 0000000..8219799 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/repositories/CouponRepository.java @@ -0,0 +1,30 @@ +package com.a1.nextlocation.data.db.repositories; + +import android.content.Context; + +import androidx.lifecycle.LiveData; + +import com.a1.nextlocation.data.Coupon; +import com.a1.nextlocation.data.db.dao.CouponDao; +import com.a1.nextlocation.data.db.Database; + +import java.util.List; + +public class CouponRepository { + private CouponDao mCouponDao; + private LiveData> mAllCoupons; + + public CouponRepository(Context context) { + Database db = Database.getDatabase(context); + mCouponDao = db.couponDao(); + mAllCoupons = mCouponDao.selectAll(); + } + + public LiveData> getAllCoupons() { + return mAllCoupons; + } + + public Coupon getCoupon(String code) { + return mCouponDao.selectCouponByCode(code); + } +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/repositories/LocationRepository.java b/app/src/main/java/com/a1/nextlocation/data/db/repositories/LocationRepository.java new file mode 100644 index 0000000..7cdb548 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/repositories/LocationRepository.java @@ -0,0 +1,30 @@ +package com.a1.nextlocation.data.db.repositories; + +import android.content.Context; + +import androidx.lifecycle.LiveData; + +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.db.Database; +import com.a1.nextlocation.data.db.dao.LocationDao; + +import java.util.List; + +public class LocationRepository { + private LocationDao mLocationDao; + private LiveData> mAllLocations; + + public LocationRepository(Context context) { + Database db = Database.getDatabase(context); + mLocationDao = db.locationDao(); + mAllLocations = mLocationDao.selectAll(); + } + + public LiveData> getAllLocations() { + return mAllLocations; + } + + public Location getLocationByName(String name) { + return mLocationDao.getLocationByName(name); + } +} diff --git a/app/src/main/java/com/a1/nextlocation/data/db/repositories/RouteRepository.java b/app/src/main/java/com/a1/nextlocation/data/db/repositories/RouteRepository.java new file mode 100644 index 0000000..0247951 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/db/repositories/RouteRepository.java @@ -0,0 +1,30 @@ +package com.a1.nextlocation.data.db.repositories; + +import android.content.Context; + +import androidx.lifecycle.LiveData; + +import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.data.db.Database; +import com.a1.nextlocation.data.db.dao.RouteDao; + +import java.util.List; + +public class RouteRepository { + private RouteDao mRouteDao; + private LiveData> mAllRoutes; + + public RouteRepository(Context context) { + Database db = Database.getDatabase(context); + mRouteDao = db.routeDao(); + mAllRoutes = mRouteDao.getAll(); + } + + public LiveData> getAllRoutes() { + return mAllRoutes; + } + + public Route getRouteByName(String name) { + return mRouteDao.getRouteByName(name); + } +} 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 7610b2a..4314101 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java @@ -1,20 +1,49 @@ package com.a1.nextlocation.fragments; +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationManager; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.a1.nextlocation.R; +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.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; + public class HomeFragment extends Fragment { + private final String userAgent = "com.ai.nextlocation.fragments"; + private MapView mapView; + private final int REQUEST_PERMISSIONS_REQUEST_CODE = 1; + private final String TAG = HomeFragment.class.getCanonicalName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + requestPermissionsIfNecessary( + // if you need to show the current location request FINE_LOCATION permission + Manifest.permission.ACCESS_FINE_LOCATION, + // WRITE_EXTERNAL_STORAGE is required in order to show the map + Manifest.permission.WRITE_EXTERNAL_STORAGE); } @@ -23,5 +52,73 @@ public class HomeFragment extends Fragment { Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_home, container, false); + + + } + + private void initMap(@NonNull View view) { + // set the user agent + Configuration.getInstance().setUserAgentValue(userAgent); + + // create the map view + mapView = (MapView) view.findViewById(R.id.mapView); + mapView.setDestroyMode(false); + mapView.setTag("mapView"); + mapView.setMultiTouchControls(true); + + // get the location provider + GpsMyLocationProvider gpsMyLocationProvider = new GpsMyLocationProvider(this.requireContext()); + + // add the compass overlay + CompassOverlay compassOverlay = new CompassOverlay(requireContext(),new InternalCompassOrientationProvider(requireContext()),mapView); + compassOverlay.enableCompass(); + mapView.getOverlays().add(compassOverlay); + + // add the location overlay + MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(gpsMyLocationProvider, mapView); + mLocationOverlay.enableFollowLocation(); + mLocationOverlay.enableMyLocation(); + mapView.getOverlays().add(mLocationOverlay); + + // add the zoom controller + IMapController mapController = mapView.getController(); + mapController.setZoom(15.0); + + // add location manager and set the start point + LocationManager locationManager = (LocationManager) requireActivity().getSystemService(Context.LOCATION_SERVICE); + + try { + Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + GeoPoint startPoint = new GeoPoint(location.getLatitude(), location.getLongitude()); + mapController.setCenter(startPoint); + + } catch (SecurityException e) { + Log.d(TAG, "onViewCreated: exception while getting location: " + e.getLocalizedMessage()); + + requestPermissionsIfNecessary( + // if you need to show the current location request FINE_LOCATION permission + Manifest.permission.ACCESS_FINE_LOCATION, + // WRITE_EXTERNAL_STORAGE is required in order to show the map + Manifest.permission.WRITE_EXTERNAL_STORAGE); + + } + + } + private void requestPermissionsIfNecessary(String... permissions) { + ArrayList permissionsToRequest = new ArrayList<>(); + if (this.getContext() != null) + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this.getContext(), permission) + != PackageManager.PERMISSION_GRANTED) { + // Permission is not granted + permissionsToRequest.add(permission); + } + } + if (permissionsToRequest.size() > 0 && this.getActivity() != null) { + ActivityCompat.requestPermissions( + this.getActivity(), + permissionsToRequest.toArray(new String[0]), + REQUEST_PERMISSIONS_REQUEST_CODE); + } } } \ No newline at end of file