diff --git a/.DS_Store b/.DS_Store index 52a72a3ff8768a8f1b86ca731e57d0f3c78dbc09..938051f6423de17db660b1124187ac42d0379550 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/MushroomsTracker/Mushrooms Tracker.zip b/MushroomsTracker/Mushrooms Tracker.zip new file mode 100644 index 0000000000000000000000000000000000000000..9f1f67977b62151edc7fb7b4ae65ec876e9ac8f2 Binary files /dev/null and b/MushroomsTracker/Mushrooms Tracker.zip differ diff --git a/MushroomsTracker/app/build.gradle b/MushroomsTracker/app/build.gradle index de35eb379292be45426dcd2562e53bf2a626268a..4fcc507b7c9f389dcd41139a4dbeaa3e68762572 100644 --- a/MushroomsTracker/app/build.gradle +++ b/MushroomsTracker/app/build.gradle @@ -6,12 +6,12 @@ plugins { android { namespace 'com.example.mushroomstracker' - compileSdk 32 + compileSdk 33 defaultConfig { applicationId "com.example.mushroomstracker" minSdk 29 - targetSdk 32 + targetSdk 33 versionCode 1 versionName "1.0" @@ -44,6 +44,12 @@ dependencies { implementation 'com.google.android.gms:play-services-location:18.0.0' implementation 'com.google.maps.android:android-maps-utils:2.2.3' implementation 'com.google.maps.android:maps-utils-ktx:3.2.0' - + implementation 'androidx.sqlite:sqlite-ktx:2.3.0' implementation 'com.google.android.material:material:1.4.0' + implementation "androidx.camera:camera-core:1.2.1" + implementation "androidx.camera:camera-camera2:1.2.1" + implementation "androidx.camera:camera-lifecycle:1.2.1" + implementation "androidx.camera:camera-video:1.2.1" + implementation "androidx.camera:camera-view:1.2.1" + implementation "androidx.camera:camera-extensions:1.2.1" } \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/AndroidManifest.xml b/MushroomsTracker/app/src/main/AndroidManifest.xml index 9ac4b6de6edc3f21d540e6f3bdeeda2031b05e46..a59e65d3efcd0424aee53592bde57e82f0536662 100644 --- a/MushroomsTracker/app/src/main/AndroidManifest.xml +++ b/MushroomsTracker/app/src/main/AndroidManifest.xml @@ -3,9 +3,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> + <uses-feature android:name="android.hardware.camera"/> + <uses-feature android:name="android.hardware.camera.any" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.CAMERA"/> <application android:allowBackup="false" @@ -16,9 +21,7 @@ android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> - <activity - android:name=".MapsActivity" - android:theme="@style/SplashTheme" + <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -26,6 +29,17 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity + android:name=".MapsActivity" + android:theme="@style/SplashTheme" + android:exported="true"> + </activity> + + <activity + android:name=".MapsDraw" + android:theme="@style/SplashTheme" + android:exported="true"> + </activity> <meta-data android:name="com.google.android.geo.API_KEY" diff --git a/MushroomsTracker/app/src/main/ic_photo-playstore.png b/MushroomsTracker/app/src/main/ic_photo-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..513500db5f4af01aae044fcd10464f8733b4708c Binary files /dev/null and b/MushroomsTracker/app/src/main/ic_photo-playstore.png differ diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/Champignon.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/Champignon.kt new file mode 100644 index 0000000000000000000000000000000000000000..00245f7fb38b6b7868f0685dd8215fb52ea03f89 --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/Champignon.kt @@ -0,0 +1,10 @@ +package com.example.mushroomstracker + +import com.google.android.gms.maps.model.LatLng + +class Champignon(name: String, description: String, quantity: String, location: LatLng) { + val name = name + val description = description + val quantity = quantity + val location = location +} \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/DatabaseHelper.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/DatabaseHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..9d26aa677dc4b39fd75d6540cddd801265d94889 --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/DatabaseHelper.kt @@ -0,0 +1,25 @@ +package com.example.mushroomstracker + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper + +class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, "database.db", null, 1) { + override fun onCreate(db: SQLiteDatabase?) { + val cueilletteTable = "CREATE TABLE CUEILLETTE(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, COMMENTAIRE TEXT);" + db?.execSQL(cueilletteTable) + val parcoursTable = "CREATE TABLE PARCOURS(LONGITUDE REAL NOT NULL, LATITUDE REAL NOT NULL, ID_CUEILLETTE INTEGER NOT NULL, FOREIGN KEY (ID_CUEILLETTE) REFERENCES CUEILLETTE(ID));" + db?.execSQL(parcoursTable) + val mushroomTable = "CREATE TABLE CHAMPIGNON(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, DESCRIPTION TEXT, DATE TEXT NOT NULL, QUANTITY INTEGER NOT NULL, IMAGE TEXT, LONGITUDE REAL NOT NULL, LATITUDE REAL NOT NULL, ID_CUEILLETTE INTEGER NOT NULL, FOREIGN KEY (ID_CUEILLETTE) REFERENCES CUEILLETTE(ID));" + db?.execSQL(mushroomTable) + } + + override fun onUpgrade(db: SQLiteDatabase?, p1: Int, p2: Int) { + db?.execSQL("DROP TABLE IF EXISTS CHAMPIGNON") + db?.execSQL("DROP TABLE IF EXISTS PARCOURS") + db?.execSQL("DROP TABLE IF EXISTS CUEILLETTE") + if (db != null) { + onCreate(db) + } + } +} \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MainActivity.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..b672d0a97d39c86443630713be6bbecd605ec06d --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MainActivity.kt @@ -0,0 +1,76 @@ +package com.example.mushroomstracker + +import android.Manifest +import android.annotation.SuppressLint +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.os.Build +import android.os.Bundle +import android.provider.MediaStore +import android.util.Log +import android.widget.Button +import android.widget.ImageButton +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageCapture +import androidx.camera.core.ImageCaptureException +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.example.mushroomstracker.databinding.ActivityMainBinding +import com.google.android.material.floatingactionbutton.FloatingActionButton +import java.io.File +import java.text.SimpleDateFormat +import java.util.* + +class MainActivity : AppCompatActivity() { + private lateinit var viewBinding: ActivityMainBinding + private var imageCapture: ImageCapture? = null + private lateinit var db: SQLiteDatabase + private var cueillettes = mutableListOf<String>() + + @SuppressLint("Recycle", "Range") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + db = DatabaseHelper(this).writableDatabase + /*db.execSQL("DELETE FROM CUEILLETTE") + db.execSQL("DELETE FROM CHAMPIGNON") + db.execSQL("DELETE FROM PARCOURS")*/ + + val button = findViewById<Button>(R.id.button_new_picking) + button.setOnClickListener { + val intent = Intent(this, MapsActivity::class.java) + startActivity(intent) + } + + val selectQuery = "SELECT * FROM CUEILLETTE" + val cursor: Cursor? = db.rawQuery(selectQuery, null) + var currentName: String + + if (cursor != null) { + if(cursor.moveToFirst()){ + do { + currentName = cursor.getString(cursor.getColumnIndex("NAME")) + cueillettes.add(currentName) + } while (cursor.moveToNext()) + } + } else { + Toast.makeText(this, "Je suis null", Toast.LENGTH_SHORT).show() + } + db.close() + val rv_items = findViewById<RecyclerView>(R.id.recycler_view) + rv_items.layoutManager = LinearLayoutManager(this) + rv_items.adapter = RecyclerAdapter(cueillettes) + } +} \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsActivity.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsActivity.kt index 09f56a7e2343df98c96f5b6cf93f6782d2bd716f..8be7041d9e5458d83b42b0399468c77a2f40691c 100644 --- a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsActivity.kt +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsActivity.kt @@ -1,12 +1,35 @@ package com.example.mushroomstracker +import android.Manifest import android.annotation.SuppressLint +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.graphics.BitmapFactory +import android.location.Location +import android.location.LocationManager +import android.os.Build import android.os.Bundle import android.os.SystemClock +import android.provider.MediaStore +import android.util.Log +import android.widget.Button import android.widget.EditText +import android.widget.ImageButton import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageCapture +import androidx.camera.core.ImageCaptureException +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat import com.example.mushroomstracker.databinding.ActivityMapsBinding import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap @@ -16,11 +39,34 @@ import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.maps.model.PolylineOptions +import java.text.SimpleDateFormat +import java.time.LocalDate +import java.util.* +import kotlin.properties.Delegates class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener { private lateinit var map: GoogleMap private lateinit var binding: ActivityMapsBinding private val presenter = MapPresenter(this) + private var imageCapture: ImageCapture? = null + private var imagePath: String? = null + private lateinit var db: SQLiteDatabase + private var id_cueillette: Int = 0 + private val champiList = mutableListOf<Champignon>() + + companion object { + private const val TAG = "CameraXApp" + private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" + private const val REQUEST_CODE_PERMISSIONS = 10 + private val REQUIRED_PERMISSIONS = + mutableListOf ( + Manifest.permission.CAMERA + ).apply { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { + add(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + }.toTypedArray() + } override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.AppTheme) @@ -43,6 +89,7 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarker } } presenter.onViewCreated() + db = DatabaseHelper(this).writableDatabase } @SuppressLint("PotentialBehaviorOverride") @@ -64,11 +111,45 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarker private fun startTracking() { map.clear() - presenter.startTracking() + db = DatabaseHelper(this).writableDatabase + val selectQuery = "SELECT COUNT(*) FROM CUEILLETTE" + val cursor: Cursor? = db.rawQuery(selectQuery, null) + if (cursor != null) { + if (cursor.moveToFirst()) { + id_cueillette = cursor.getInt(0) + 1 + } + } + println("id = $id_cueillette") + val builder = AlertDialog.Builder(this) + val inflater = layoutInflater + builder.setTitle("Ajouter un marqueur") + val dialogLayout = inflater.inflate(R.layout.new_cueillette, null) + builder.setView(dialogLayout) + // remplir formulaire + + val name = dialogLayout.findViewById<EditText>(R.id.cueilletteNameEditText) + val commentaire = dialogLayout.findViewById<EditText>(R.id.cueilletteCommentaireEditText) + + var pickingName: String + var pickingCom: String + pickingName = "" + pickingCom = "" + + builder.setPositiveButton("OK") { _, _ -> + pickingName = name.text.toString() + pickingCom = commentaire.text.toString() + db.execSQL("INSERT INTO CUEILLETTE VALUES('$id_cueillette', '$pickingName', '$pickingCom')") + presenter.startTracking() + } + + builder.setNegativeButton("Fermer") { _, _ -> } + builder.show() } private fun stopTracking() { presenter.stopTracking() + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) } @SuppressLint("MissingPermission") @@ -76,6 +157,9 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarker if (ui.currentLocation != null && ui.currentLocation != map.cameraPosition.target) { map.isMyLocationEnabled = true map.animateCamera(CameraUpdateFactory.newLatLngZoom(ui.currentLocation, 17f)) + for (champi in champiList) { + saveMarkerOnMap(champi.location, champi.name, champi.description, champi.quantity) + } } drawRoute(ui.userPath) } @@ -83,29 +167,78 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarker private fun drawRoute(locations: List<LatLng>) { val polylineOptions = PolylineOptions() map.clear() + if (locations.isNotEmpty()) { + db.execSQL("INSERT INTO PARCOURS VALUES('${locations?.get(locations.size - 1)?.longitude}', '${locations?.get(locations.size - 1)?.latitude}', '$id_cueillette')") + } val points = polylineOptions.points points.addAll(locations) map.addPolyline(polylineOptions) } + private fun saveMarkerOnMap(location: LatLng, title: String, description: String, quantity: String) { + val marker = MarkerOptions().position(location) + marker.title(title) + marker.snippet("Description : $description\nQuantité : $quantity") + map.addMarker(marker) + } + @SuppressLint("InflateParams") private fun placeMarkerOnMap(location: LatLng){ - Toast.makeText(this, "HELP", Toast.LENGTH_SHORT).show() val builder = AlertDialog.Builder(this) val inflater = layoutInflater builder.setTitle("Ajouter un marqueur") val dialogLayout = inflater.inflate(R.layout.new_marker, null) builder.setView(dialogLayout) + + /*if (allPermissionsGranted()) { + startCamera() + } else { + ActivityCompat.requestPermissions( + this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS + ) + } + + // Set up the listeners for take photo and video capture buttons + val imageButton = findViewById<Button>(R.id.image_btn) + imageButton.setOnClickListener { + takePhoto() + }*/ + val title = dialogLayout.findViewById<EditText>(R.id.markerTitleEditText) - val description = dialogLayout.findViewById<EditText>(R.id.markerDescriptionEditText) - val quantity = dialogLayout.findViewById<EditText>(R.id.markerQuantiteEditText) + val desc = dialogLayout.findViewById<EditText>(R.id.markerDescriptionEditText) + val quant = dialogLayout.findViewById<EditText>(R.id.markerQuantiteEditText) + + //val content = ContentValues() builder.setPositiveButton("OK") { _, _ -> val marker = MarkerOptions().position(location) marker.title(title.text.toString()) - marker.snippet("Description : " + description.text.toString() + "\n" + "Quantité : " + quantity.text.toString()) + marker.snippet("Description : " + desc.text.toString() + "\n" + "Quantité : " + quant.text.toString()) map.addMarker(marker) + + /*if (imagePath != null) { + content.put("image", imagePath.toString()) + } + content.put("name", title.text.toString()) + content.put("description", desc.text.toString()) + content.put("quantity", quant.text.toString().toInt()) + content.put("date", LocalDate.now().toString()) + content.put("longitude", location.longitude) + content.put("latitude", location.latitude) + content.put("id_cueillette", id_cueillette) + */ + + val name = title.text.toString() + val description = desc.text.toString() + val quantity = quant.text.toString().toInt() + val date = LocalDate.now().toString() + val longitude = location.longitude + val latitude = location.latitude + println("TEST $id_cueillette") + db.execSQL("INSERT INTO CHAMPIGNON(NAME, DESCRIPTION, QUANTITY, DATE, LONGITUDE, LATITUDE, ID_CUEILLETTE) VALUES ('$name', '$description', '$quantity', '$date', $longitude, $latitude, $id_cueillette)") + champiList.add(Champignon(name, description, quantity.toString(), LatLng(latitude, longitude))) + //imagePath = null } builder.setNegativeButton("Fermer") { _, _ -> } @@ -128,5 +261,92 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarker builder.show() return true } + + private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { + ContextCompat.checkSelfPermission( + baseContext, it) == PackageManager.PERMISSION_GRANTED + } + + @SuppressLint("MissingSuperCall") + override fun onRequestPermissionsResult( + requestCode: Int, permissions: Array<String>, grantResults: + IntArray) { + if (requestCode == REQUEST_CODE_PERMISSIONS) { + if (allPermissionsGranted()) { + startCamera() + } else { + Toast.makeText(this, + "Permissions not granted by the user.", + Toast.LENGTH_SHORT).show() + finish() + } + } + } + + private fun startCamera() { + val cameraProviderFuture = ProcessCameraProvider.getInstance(this) + + cameraProviderFuture.addListener({ + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + val previewView = findViewById<PreviewView>(R.id.viewFinder) + + val preview = Preview.Builder().build() + preview.setSurfaceProvider(previewView.surfaceProvider) + + imageCapture = ImageCapture.Builder().build() + + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + + try { + cameraProvider.unbindAll() + cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture) + } catch(exc: java.lang.Exception) { + Log.e(TAG, "Use case binding failed", exc) + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun takePhoto() { + // Get a stable reference of the modifiable image capture use case + val imageCapture = imageCapture ?: return + + // Create time stamped name and MediaStore entry. + val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US) + .format(System.currentTimeMillis()) + val contentValues = ContentValues().apply { + put(MediaStore.MediaColumns.DISPLAY_NAME, name) + put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") + if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image") + } + } + + // Create output options object which contains file + metadata + val outputOptions = ImageCapture.OutputFileOptions + .Builder(contentResolver, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + contentValues) + .build() + + // Set up image capture listener, which is triggered after photo has + // been taken + imageCapture.takePicture( + outputOptions, + ContextCompat.getMainExecutor(this), + object : ImageCapture.OnImageSavedCallback { + override fun onError(exc: ImageCaptureException) { + Log.e(TAG, "Photo capture failed: ${exc.message}", exc) + } + + override fun + onImageSaved(output: ImageCapture.OutputFileResults){ + val msg = "Photo capture succeeded: ${output.savedUri}" + Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() + imagePath = output.savedUri?.path + Log.d(TAG, msg) + } + } + ) + } } diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsDraw.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsDraw.kt new file mode 100644 index 0000000000000000000000000000000000000000..2cc23ecd47de70b10de77764ad86b18c21e40f12 --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MapsDraw.kt @@ -0,0 +1,192 @@ +package com.example.mushroomstracker + +import android.Manifest +import android.annotation.SuppressLint +import android.app.NotificationManager +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.graphics.BitmapFactory +import android.location.Location +import android.location.LocationManager +import android.os.Build +import android.os.Bundle +import android.os.SystemClock +import android.provider.MediaStore +import android.util.Log +import android.widget.Button +import android.widget.EditText +import android.widget.ImageButton +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageCapture +import androidx.camera.core.ImageCaptureException +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat +import androidx.core.content.ContextCompat +import com.example.mushroomstracker.databinding.ActivityMapsBinding +import com.google.android.gms.maps.CameraUpdateFactory +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.OnMapReadyCallback +import com.google.android.gms.maps.SupportMapFragment +import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.maps.model.Marker +import com.google.android.gms.maps.model.MarkerOptions +import com.google.android.gms.maps.model.PolylineOptions +import java.io.LineNumberReader +import java.text.SimpleDateFormat +import java.time.LocalDate +import java.util.* +import kotlin.properties.Delegates + +class MapsDraw : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener { + private lateinit var map: GoogleMap + private lateinit var binding: ActivityMapsBinding + private val presenter = MapPresenter(this) + private lateinit var db: SQLiteDatabase + private var id_cueillette: Int = 0 + private val champiList = mutableListOf<Champignon>() + + override fun onCreate(savedInstanceState: Bundle?) { + setTheme(R.style.AppTheme) + super.onCreate(savedInstanceState) + + id_cueillette = intent.getIntExtra("id_cueillette", 0) + + binding = ActivityMapsBinding.inflate(layoutInflater) + setContentView(binding.root) + + val mapFragment = supportFragmentManager + .findFragmentById(R.id.map) as SupportMapFragment + mapFragment.getMapAsync(this) + + presenter.onViewCreated() + db = DatabaseHelper(this).writableDatabase + } + + @SuppressLint("PotentialBehaviorOverride", "Range") + override fun onMapReady(googleMap: GoogleMap) { + map = googleMap + + presenter.onMapLoaded() + map.uiSettings.isZoomControlsEnabled = true + + var cursor: Cursor? = db.rawQuery("SELECT * FROM CHAMPIGNON WHERE ID_CUEILLETTE=$id_cueillette", null) + if (cursor != null) { + if (cursor.moveToFirst()) { + do { + var name = cursor.getString(cursor.getColumnIndex("NAME")) + var description = cursor.getString(cursor.getColumnIndex("DESCRIPTION")) + var quantity = cursor.getString(cursor.getColumnIndex("QUANTITY")) + var longitude = cursor.getDouble(cursor.getColumnIndex("LONGITUDE")) + var latitude = cursor.getDouble(cursor.getColumnIndex("LATITUDE")) + var tmp = LatLng(latitude, longitude) + champiList.add(Champignon(name, description, quantity, tmp)) + } while (cursor.moveToNext()) + } + } + + val latLngLst = mutableListOf<LatLng>() + cursor = db.rawQuery("SELECT * FROM PARCOURS WHERE ID_CUEILLETTE=$id_cueillette", null) + if (cursor != null) { + if (cursor.moveToFirst()) { + do { + var longitude = cursor.getDouble(cursor.getColumnIndex("LONGITUDE")) + var latitude = cursor.getDouble(cursor.getColumnIndex("LATITUDE")) + latLngLst.add(LatLng(latitude, longitude)) + drawRoute(latLngLst) + } while (cursor.moveToNext()) + } + } + map.setOnMarkerClickListener(this@MapsDraw) + presenter.ui.observe(this) { ui -> + updateUi(ui) + } + } + + + @SuppressLint("MissingPermission") + private fun updateUi(ui: Ui) { + if (ui.currentLocation != null && ui.currentLocation != map.cameraPosition.target) { + map.isMyLocationEnabled = true + map.animateCamera(CameraUpdateFactory.newLatLngZoom(ui.currentLocation, 17f)) + for (champi in champiList) { + saveMarkerOnMap(champi.location, champi.name, champi.description, champi.quantity) + } + if(compareDistance(ui.currentLocation)) { + // sendNotification + } + } + } + + private fun compareDistance(currentLocation : LatLng): Boolean { + var loc = Location("") + loc.longitude = currentLocation.longitude + loc.latitude = currentLocation.latitude + for (champi in champiList) { + var loc2 = Location("") + loc2.longitude = champi.location.longitude + loc2.latitude = champi.location.latitude + if (loc.distanceTo(loc2) < 20) { + return true + } + } + return false + } + + /*@SuppressLint("ServiceCast") + private fun showNotification() { + // Créer une notification + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle("Vous êtes proche de la destination") + .setContentText("Vous êtes à moins de 100 mètres de la destination") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + notificationManager.notify(NOTIFICATION_ID, notification) + }*/ + + private fun drawRoute(locations: List<LatLng>) { + val polylineOptions = PolylineOptions() + map.clear() + val points = polylineOptions.points + points.addAll(locations) + map.addPolyline(polylineOptions) + } + + @SuppressLint("InflateParams") + private fun saveMarkerOnMap(location: LatLng, title: String, description: String, quantity: String){ + val marker = MarkerOptions().position(location) + marker.title(title) + marker.snippet("Description : $description\nQuantité : $quantity") + map.addMarker(marker) + } + + @SuppressLint("ServiceCast", "InflateParams", "SimpleDateFormat") + override fun onMarkerClick(marker: Marker): Boolean { + val builder = AlertDialog.Builder(this) + builder.setTitle(marker.title) + builder.setMessage(marker.snippet) + builder.setPositiveButton("Supprimer") { _, _ -> + AlertDialog.Builder(this).setTitle("Supprimer le marker") + .setMessage("Voulez vous vraiment supprimer ce marqueur ?") + .setNegativeButton("Non") { _, _ -> } + .setPositiveButton("Oui") { _, _ -> marker.remove() } + .show() + } + builder.setNegativeButton("Fermer") { _, _ -> } + builder.show() + return true + } +} + diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MyAdapter.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MyAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..3196ef0b2d6bd3d1fcc998d1b26d63ddcb355186 --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/MyAdapter.kt @@ -0,0 +1,40 @@ +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.example.mushroomstracker.R + +class MyAdapter(private val mList: List<String>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() { + + // create new views + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + // inflates the card_view_design view + // that is used to hold list item + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_layout, parent, false) + + return ViewHolder(view) + } + + // binds the list items to a view + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + + val ItemsViewModel = mList[position] + + // sets the text to the textview from our itemHolder class + holder.textView.text = ItemsViewModel + + } + + // return the number of the items in the list + override fun getItemCount(): Int { + return mList.size + } + + // Holds the views for adding it to image and text + class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) { + val textView: TextView = itemView.findViewById(R.id.card_view) + } +} diff --git a/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/RecyclerAdapter.kt b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/RecyclerAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..af47eec383574c3b67985831c686fdd0173d9e42 --- /dev/null +++ b/MushroomsTracker/app/src/main/java/com/example/mushroomstracker/RecyclerAdapter.kt @@ -0,0 +1,39 @@ +package com.example.mushroomstracker +import android.content.Intent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import android.widget.Toast +import androidx.recyclerview.widget.RecyclerView + +class RecyclerAdapter (private var titles: List<String>) : + RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() { + + class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val itemTitle: TextView = itemView.findViewById<TextView>(R.id.tv_name) + + init { + itemView.setOnClickListener { v: View -> + val position: Int = adapterPosition + Toast.makeText(itemView.context, "You clicked on Item # ${position + 1}", Toast.LENGTH_SHORT).show() + val intent = Intent(itemView.context, MapsDraw::class.java) + intent.putExtra("id_cueillette", position + 1) + itemView.context.startActivity(intent) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false) + return ViewHolder(v) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.itemTitle.text = titles[position] + } + + override fun getItemCount(): Int { + return titles.size + } +} \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/res/drawable/ic_photo_foreground.xml b/MushroomsTracker/app/src/main/res/drawable/ic_photo_foreground.xml new file mode 100644 index 0000000000000000000000000000000000000000..25406081465876f1ec82c8f59b2fdfb728316d34 --- /dev/null +++ b/MushroomsTracker/app/src/main/res/drawable/ic_photo_foreground.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108" + android:tint="#484444"> + <group android:scaleX="2.61" + android:scaleY="2.61" + android:translateX="22.68" + android:translateY="22.68"> + <path + android:fillColor="@android:color/white" + android:pathData="M3,4V1h2v3h3v2H5v3H3V6H0V4H3zM6,10V7h3V4h7l1.83,2H21c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H5c-1.1,0 -2,-0.9 -2,-2V10H6zM13,19c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5s-5,2.24 -5,5S10.24,19 13,19zM9.8,14c0,1.77 1.43,3.2 3.2,3.2s3.2,-1.43 3.2,-3.2s-1.43,-3.2 -3.2,-3.2S9.8,12.23 9.8,14z"/> + </group> +</vector> diff --git a/MushroomsTracker/app/src/main/res/layout/activity_main.xml b/MushroomsTracker/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..121e6ca220bf250d23a2c445248354d1fee4e83a --- /dev/null +++ b/MushroomsTracker/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <Button + android:id="@+id/button_new_picking" + android:layout_width="388dp" + android:layout_height="48dp" + android:text="@string/main_new_picking" + tools:ignore="MissingConstraints" + tools:layout_editor_absoluteX="16dp" + tools:layout_editor_absoluteY="16dp" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_view" + android:layout_width="376dp" + android:layout_height="623dp" + android:layout_marginTop="64dp" + app:layout_constraintEnd_toEndOf="@id/button_new_picking" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="@+id/button_new_picking" + app:layout_constraintTop_toTopOf="@id/button_new_picking" + tools:ignore="MissingConstraints" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/res/layout/item_layout.xml b/MushroomsTracker/app/src/main/res/layout/item_layout.xml new file mode 100644 index 0000000000000000000000000000000000000000..213ec8bf8576c6253357219fc765d648e939067d --- /dev/null +++ b/MushroomsTracker/app/src/main/res/layout/item_layout.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/card_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:clickable="true" + android:focusable="true" + android:foreground="?selectableItemBackground" + app:cardCornerRadius="10dp"> + + <RelativeLayout + android:id="@+id/rl_wrapper" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="20dp"> + + <ImageView + android:id="@+id/iv_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginStart="10dp" + android:layout_marginTop="10dp" + android:layout_marginEnd="10dp" + android:layout_marginBottom="10dp" + android:contentDescription="@string/champi" /> + + <TextView + android:id="@+id/tv_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:text="@string/tmp_text" + android:textColor="@android:color/black" /> + + </RelativeLayout> +</androidx.cardview.widget.CardView> diff --git a/MushroomsTracker/app/src/main/res/layout/new_cueillette.xml b/MushroomsTracker/app/src/main/res/layout/new_cueillette.xml new file mode 100644 index 0000000000000000000000000000000000000000..d403c7290920f77491646c0af3573b01198f3230 --- /dev/null +++ b/MushroomsTracker/app/src/main/res/layout/new_cueillette.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <TextView + android:id="@+id/cueilletteName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="8dp" + android:text="@string/nom_cueillette" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <EditText + android:id="@+id/cueilletteNameEditText" + android:layout_width="300dp" + android:layout_height="40dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="8dp" + android:autofillHints="" + android:ems="10" + android:inputType="textPersonName" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.494" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/cueilletteName" + tools:ignore="LabelFor" /> + + <TextView + android:id="@+id/cueilletteCommentaire" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="88dp" + android:layout_marginEnd="8dp" + android:text="@string/commentaire" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <EditText + android:id="@+id/cueilletteCommentaireEditText" + android:layout_width="300dp" + android:layout_height="40dp" + android:layout_marginStart="8dp" + android:layout_marginTop="16dp" + android:layout_marginEnd="8dp" + android:autofillHints="" + android:ems="10" + android:inputType="textPersonName" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.494" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/cueilletteCommentaire" + tools:ignore="LabelFor" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/res/layout/new_marker.xml b/MushroomsTracker/app/src/main/res/layout/new_marker.xml index d9ddfe585b3e53ca5c100009042bbb706b56964e..9b808f17277452338b784cb23cdafa65723a80f1 100644 --- a/MushroomsTracker/app/src/main/res/layout/new_marker.xml +++ b/MushroomsTracker/app/src/main/res/layout/new_marker.xml @@ -88,4 +88,26 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + <androidx.camera.view.PreviewView + android:id="@+id/viewFinder" + android:layout_width="159dp" + android:layout_height="159dp" + android:layout_marginTop="268dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:ignore="MissingConstraints" /> + + <Button + android:id="@+id/image_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="436dp" + android:text="Button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.498" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:ignore="MissingConstraints" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/res/values/ic_photo_background.xml b/MushroomsTracker/app/src/main/res/values/ic_photo_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..143a98d3dcd42d10af41b0c92ef728067fd16347 --- /dev/null +++ b/MushroomsTracker/app/src/main/res/values/ic_photo_background.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="ic_photo_background">#ADAFAD</color> +</resources> \ No newline at end of file diff --git a/MushroomsTracker/app/src/main/res/values/strings.xml b/MushroomsTracker/app/src/main/res/values/strings.xml index 68fa3fb9586fa95c68a5a01ceb1b025096e25c13..453c4b17334374e0d3802e61d2292ff87c57d97d 100644 --- a/MushroomsTracker/app/src/main/res/values/strings.xml +++ b/MushroomsTracker/app/src/main/res/values/strings.xml @@ -13,4 +13,9 @@ <string name="display_marker_title">Nom du champignon</string> <string name="display_marker_description">Description</string> <string name="display_marker_quantite">Quantité</string> + <string name="main_new_picking">Nouvelle cueillette</string> + <string name="nom_cueillette">Nom</string> + <string name="commentaire">Commentaire</string> + <string name="champi">Champi</string> + <string name="tmp_text">Texte temporaire</string> </resources> diff --git a/MushroomsTracker/build.gradle b/MushroomsTracker/build.gradle index cf11c024464d3e2cddef15af0ce6770aa3e1539e..120a780192a72995e10c46b4200adfd17c5a69e4 100644 --- a/MushroomsTracker/build.gradle +++ b/MushroomsTracker/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.3.1' apply false - id 'com.android.library' version '7.3.1' apply false + id 'com.android.application' version '7.2.2' apply false + id 'com.android.library' version '7.2.2' apply false id 'org.jetbrains.kotlin.android' version '1.7.20' apply false id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false } \ No newline at end of file