Compare commits
No commits in common. 'master' and 'arthur' have entirely different histories.
@ -1 +0,0 @@
|
||||
Geocaching
|
Before Width: | Height: | Size: 352 KiB |
@ -1,61 +1,5 @@
|
||||
<p align="center">
|
||||
<img src="Documentation/banner.png" />
|
||||
</p>
|
||||
|
||||

|
||||

|
||||
</br>
|
||||
|
||||
|
||||
**RoadTrip** est une application mobile Android qui permet aux utilisateurs de créer des itinéraires de voyage.
|
||||
|
||||

|
||||
|
||||
|
||||
## 🪶 Fonctionnalités
|
||||
|
||||
Lors de votre arrivée sur l'application, vous retrouverez une carte avec votre emplacement actuel. </br>Naviguez sur la carte pour découvrir vos environs.
|
||||
|
||||
Appuyez 2 fois sur la carte pour créer un point d'intérêt, ajoutez en plusieurs afin de construire un itinéraire.
|
||||
|
||||
Validez ensuite votre voyage en cliquant sur le bouton ✅ en bas à gauche de l'écran et donnez lui un nom.
|
||||
|
||||
Retrouvez vos voyages dans l'onglet "Roadtrips" en bas de l'écran.
|
||||
|
||||
Accédez aux informations de votre voyage en cliquant dessus dans la liste déroulante. </br>Vous retrouverez la liste des points d'intérêts que vous avez ajouté, ainsi que les adresses de chacun d'entre eux.
|
||||
|
||||
Vous pouvez supprimer un voyage à tout moment avec le bouton en bas de votre écran</br>Ou vous pouvez l'éditer en rajoutant des points sur la carte et en validant.
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
## 💽 Lancer l'application
|
||||
|
||||
Une fois le dépot cloné, vous pourrez lancer l'application sur votre téléphone Android grâce aux outils fournis par Android Studio. Si vous n'avez pas de téléphone Android, vous pouvez utiliser un émulateur.
|
||||
|
||||

|
||||
|
||||
## 🤖 Made by
|
||||
|
||||
Arthur VALIN : **Arthur.VALIN@etu.uca.fr**
|
||||
|
||||
<a href = "https://codefirst.iut.uca.fr/git/arthur.valin">
|
||||
<img src ="https://codefirst.iut.uca.fr/git/avatars/041c57af1e1d1e855876d8abb5f1c143?size=870" height="50px">
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
Baptiste BONNEAU : **Baptiste.BONNEAU@etu.uca.fr**
|
||||
|
||||
<a href = "https://codefirst.iut.uca.fr/git/baptiste.bonneau">
|
||||
<img src ="https://codefirst.iut.uca.fr/git/avatars/e47d41c01439fc439a23cf6843310b05?size=870" height="50px">
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
J'ai pas fait grand chose car j'ai eu masse problème avec le projet, il a fallut modifier plein de choses dans les settings graddle.
|
||||
|
||||
J'ai laissé des commentaires dans la vue
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
@ -1,10 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.application
|
||||
|
||||
import android.app.Application
|
||||
import uca.baptistearthur.geocaching.data.BDD
|
||||
|
||||
class RTApplication: Application() {
|
||||
|
||||
val db: BDD by lazy { BDD.getInstance(this) }
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.converters
|
||||
|
||||
import android.util.Log
|
||||
import androidx.room.TypeConverter
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import java.util.*
|
||||
|
||||
class Converters {
|
||||
@TypeConverter
|
||||
fun toDate(timestamp: Long?): Date? {
|
||||
return if (timestamp == null) null else Date(timestamp)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toLong(date: Date?): Long? {
|
||||
return date?.time
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toString(places: List<Place>): String {
|
||||
return Gson().toJson(places)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toPlaces(value: String): List<Place> {
|
||||
val listType = object : TypeToken<List<Place>>() {}.type
|
||||
return Gson().fromJson(value, listType)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toRoadTripEntity(value: String?): RoadTripEntity {
|
||||
return Gson().fromJson(value, RoadTripEntity::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Date.toFrenchFormat(): String {
|
||||
val day: String = if(this.date < 10) "0${this.date}" else "${this.date}"
|
||||
val month: String = if(this.month < 10) "0${this.month+1}" else "${this.month+1}"
|
||||
val year = "${this.year + 1900}"
|
||||
val hours: String = if(this.hours < 10) "0${this.hours}" else "${this.hours}"
|
||||
val minutes: String = if(this.minutes < 10) "0${this.minutes}" else "${this.minutes}"
|
||||
|
||||
return "$day/$month/$year - ${hours}h$minutes"}
|
@ -1,28 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.data
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import uca.baptistearthur.geocaching.converters.Converters
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import androidx.room.Database
|
||||
|
||||
@Database(entities = arrayOf(RoadTripEntity::class), version=1, exportSchema = false)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class BDD : RoomDatabase(){
|
||||
|
||||
abstract fun roadTripDAO(): RoadTripDAO
|
||||
|
||||
companion object{
|
||||
private var INSTANCE: BDD ?= null
|
||||
|
||||
fun getInstance(context: Context) =
|
||||
INSTANCE ?: synchronized(this){
|
||||
val db = Room.databaseBuilder(context, BDD::class.java, "roadTripDB").build()
|
||||
INSTANCE = db
|
||||
INSTANCE!!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.data
|
||||
|
||||
import androidx.annotation.RequiresPermission.Read
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
@androidx.room.Dao
|
||||
interface RoadTripDAO {
|
||||
|
||||
@Insert
|
||||
suspend fun insertRoadTrip(r: RoadTripEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteRoadTrip(r: RoadTripEntity)
|
||||
|
||||
@Query("SELECT * FROM Roadtrip ORDER BY date")
|
||||
fun getAllRoadTrips(): Flow<MutableList<RoadTripEntity>>
|
||||
|
||||
@Query("SELECT * FROM Roadtrip WHERE id = :id")
|
||||
fun getRoadTripById(id: Int): Flow<RoadTripEntity>
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.data
|
||||
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import java.util.Date
|
||||
|
||||
class Stub {
|
||||
fun load(): MutableList<RoadTripEntity> {
|
||||
val list = listOf(
|
||||
RoadTripEntity(
|
||||
1,
|
||||
"France",
|
||||
Date(),
|
||||
listOf(Place(49.3, 49.3)).toMutableList()
|
||||
),
|
||||
RoadTripEntity(
|
||||
2,
|
||||
"Italie",
|
||||
Date(),
|
||||
listOf(Place(48.866667, 2.34533), Place(98.866667, 2.333333)).toMutableList()
|
||||
),
|
||||
RoadTripEntity(
|
||||
3,
|
||||
"Danemark",
|
||||
Date(),
|
||||
listOf(Place(48.866667, 2.333333), Place(48.866667, 2.333333)).toMutableList()
|
||||
),
|
||||
RoadTripEntity(
|
||||
4,
|
||||
"Islande",
|
||||
Date(),
|
||||
listOf(Place(48.866667, 2.333333), Place(48.866667, 2.333333), Place(48.866667, 2.333333)).toMutableList()
|
||||
),
|
||||
)
|
||||
return list.toMutableList()
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.model
|
||||
|
||||
data class Address(
|
||||
val country: String,
|
||||
val displayName: String)
|
@ -0,0 +1,14 @@
|
||||
package uca.baptistearthur.geocaching.model
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class Geocache(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val difficulty: Float,
|
||||
val placedDate: LocalDateTime,
|
||||
val backgroundImageUrl: String,
|
||||
val findCount: Int,
|
||||
val latitude: Double,
|
||||
val longitude: Double
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.model
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.*
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import uca.baptistearthur.geocaching.network.AddressNetwork
|
||||
|
||||
class Place(private val lat: Double,
|
||||
private val lon: Double,
|
||||
var address: Address = Address("unknown", "unknown"))
|
||||
: GeoPoint(lat, lon){
|
||||
suspend fun initAddress() {
|
||||
AddressNetwork.retrofit.let {
|
||||
CoroutineScope(Dispatchers.IO).async {
|
||||
address = it.getAddress(lat, lon)
|
||||
}.await()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.model
|
||||
|
||||
import android.provider.Telephony.Mms.Addr
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.google.gson.Gson
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import java.util.Date
|
||||
|
||||
@Entity(tableName = "Roadtrip")
|
||||
class RoadTripEntity(
|
||||
@PrimaryKey(autoGenerate = true) val id: Int,
|
||||
@ColumnInfo(name="name") val name: String,
|
||||
@ColumnInfo(name="date") val date: Date,
|
||||
@ColumnInfo(name="places") val places: MutableList<Place>
|
||||
){
|
||||
fun addPlaceToRoadTripList(place: Place) = places.add(place)
|
||||
fun addPlaceToRoadTripList(latitude: Double, longitude: Double) = places.add(Place(latitude, longitude))
|
||||
fun toJSON(): String = Gson().toJson(this)
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.network
|
||||
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.Query
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
|
||||
interface AddressAPI {
|
||||
@GET("/v1/reverse")
|
||||
suspend fun getAddress(
|
||||
@Query("lat") lat: Double,
|
||||
@Query("lon") lon: Double
|
||||
): Address
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.network
|
||||
|
||||
import android.util.Log
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class AddressDeserializer : JsonDeserializer<Address> {
|
||||
|
||||
override fun deserialize(
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): Address = json?.asJsonObject!!.let{
|
||||
Address(
|
||||
it.get("address").asJsonObject.get("country").asString,
|
||||
it.get("display_name").asString
|
||||
)
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.network
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
import java.lang.reflect.Type
|
||||
|
||||
|
||||
object AddressNetwork {
|
||||
|
||||
private val API_Info = object {
|
||||
val base_url = "https://forward-reverse-geocoding.p.rapidapi.com/v1/reverse/"
|
||||
val key = "19516a9900mshce10de76f99976bp10f192jsn8c8d82222baa"
|
||||
}
|
||||
|
||||
private val rateLimiter = object {
|
||||
val maxRequestsPerSecond = 2
|
||||
val intervalInMillis = (1000.0 / maxRequestsPerSecond).toLong()
|
||||
var lastRequestTime: Long = 0
|
||||
}
|
||||
|
||||
val rateLimitInterceptor = Interceptor { chain ->
|
||||
val now = System.currentTimeMillis()
|
||||
val elapsed = now - rateLimiter.lastRequestTime
|
||||
if (elapsed < rateLimiter.intervalInMillis) {
|
||||
Thread.sleep(rateLimiter.intervalInMillis - elapsed)
|
||||
}
|
||||
rateLimiter.lastRequestTime = System.currentTimeMillis()
|
||||
|
||||
chain.proceed(chain.request())
|
||||
}
|
||||
private val interceptor = HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
|
||||
private val gson = GsonBuilder().apply {
|
||||
registerTypeAdapter(Address::class.java, AddressDeserializer())
|
||||
}.create()
|
||||
|
||||
private val client = OkHttpClient.Builder()
|
||||
.addInterceptor { chain ->
|
||||
val request = chain.request().newBuilder()
|
||||
.addHeader("X-RapidAPI-Key", API_Info.key)
|
||||
.build()
|
||||
chain.proceed(request)
|
||||
}
|
||||
.addInterceptor(interceptor)
|
||||
.addInterceptor(rateLimitInterceptor)
|
||||
.build()
|
||||
|
||||
val retrofit: AddressAPI by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(API_Info.base_url)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||
.build()
|
||||
.create(AddressAPI::class.java)
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.recyclerview
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
|
||||
|
||||
class PlacesAdapter (val places: List<Place>) : RecyclerView.Adapter<PlacesViewHolder>(){
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlacesViewHolder {
|
||||
return PlacesViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.cell_place, parent, false))
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: PlacesViewHolder, position: Int) {
|
||||
holder.placeAddress.text = places[position].address.displayName
|
||||
}
|
||||
override fun getItemCount(): Int = places.size
|
||||
}
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.recyclerview
|
||||
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
class PlacesViewHolder(val cellule: View): ViewHolder(cellule) {
|
||||
|
||||
var placeAddress: TextView = cellule.findViewById(R.id.txtPlaceAddress)
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.recyclerview
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.NavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
|
||||
class RoadTripAdapter(val voyages: List<RoadTripEntity>, val navController: NavController) : RecyclerView.Adapter<RoadTripViewHolder>(){
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RoadTripViewHolder {
|
||||
return RoadTripViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.cell_one_roadtrip, parent, false), navController)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: RoadTripViewHolder, position: Int) {
|
||||
holder.roadTripAccessButton.text = "> " + if (voyages[position].name.length > 20) voyages[position].name.substring(0, 20) + "..." else voyages[position].name
|
||||
|
||||
holder.clickedRoadTrip = voyages[position]
|
||||
}
|
||||
override fun getItemCount(): Int = voyages.size
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.recyclerview
|
||||
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.navigation.NavController
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.converters.Converters
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
|
||||
class RoadTripViewHolder(val cellule: View, val navController: NavController): ViewHolder(cellule) {
|
||||
|
||||
var roadTripAccessButton: Button = cellule.findViewById(R.id.btnGetRoadTripsInfo)
|
||||
var clickedRoadTrip: RoadTripEntity? = null
|
||||
|
||||
init{
|
||||
roadTripAccessButton.setOnClickListener{
|
||||
Log.d("RoadTripViewHolder", "RoadTripViewHolder clicked: ${clickedRoadTrip?.name}")
|
||||
var clickRoadTripJSON = clickedRoadTrip?.toJSON()
|
||||
// navController.navigate(R.id.action_roadTripFragment_to_roadtripDetail)
|
||||
|
||||
val bundle = bundleOf("roadTrip" to clickRoadTripJSON)
|
||||
|
||||
navController.navigate(R.id.action_roadTripFragment_to_roadtripDetail, bundle)
|
||||
|
||||
Log.d("RoadTripViewHolder", "Data sent: ${clickedRoadTrip?.name}")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +1,47 @@
|
||||
package uca.baptistearthur.geocaching.ui.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import kotlinx.coroutines.*
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.ui.fragment.Map
|
||||
import uca.baptistearthur.geocaching.ui.fragment.Profile
|
||||
|
||||
class MainWindow: AppCompatActivity() {
|
||||
@SuppressLint("MissingInflatedId")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
val map = Map();
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.main_window)
|
||||
|
||||
val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
|
||||
val navController = findNavController(R.id.fragment_container)
|
||||
bottomNavigation.setupWithNavController(navController)
|
||||
bottomNavigation.setOnItemReselectedListener { item ->
|
||||
val reselectedDestinationId = item.itemId
|
||||
navController.popBackStack(reselectedDestinationId, inclusive = false)
|
||||
loadFragment(Map())
|
||||
val navigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
|
||||
navigation.selectedItemId= R.id.map
|
||||
navigation.setOnItemSelectedListener {
|
||||
when (it.itemId) {
|
||||
R.id.profile -> {
|
||||
loadFragment(Profile())
|
||||
true
|
||||
}
|
||||
R.id.map -> {
|
||||
loadFragment(map)
|
||||
true
|
||||
}
|
||||
R.id.list -> {
|
||||
loadFragment(uca.baptistearthur.geocaching.ui.fragment.List())
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
bottomNavigation.setOnItemSelectedListener { item ->
|
||||
NavigationUI.onNavDestinationSelected(item, navController)
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
private fun loadFragment(fragment: Fragment){
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(R.id.fragment_container, fragment)
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import org.osmdroid.bonuspack.routing.OSRMRoadManager
|
||||
import org.osmdroid.util.BoundingBox
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import uca.baptistearthur.geocaching.ui.overlay.EditMarkerOverlay
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
|
||||
|
||||
class EditRoadtripMap : Map() {
|
||||
|
||||
var roadTrip: RoadTripEntity? = null
|
||||
set(value) {
|
||||
roadTrip?:
|
||||
value?.let {
|
||||
addEditMarkerOverlay(value)
|
||||
getMapParams(value).let{
|
||||
map.controller.setCenter(it.first)
|
||||
map.controller.setZoom(it.second)
|
||||
}
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun addEditMarkerOverlay(roadTrip: RoadTripEntity){
|
||||
val editMarkerOverlay = EditMarkerOverlay(OSRMRoadManager(context, userAgent), roadTrip)
|
||||
editMarkerOverlay.addPlaces(roadTrip.places, map)
|
||||
map.overlays.add(editMarkerOverlay);
|
||||
}
|
||||
|
||||
private fun getMapParams(roadTrip: RoadTripEntity): Pair<GeoPoint, Double>{
|
||||
val boundingBox = BoundingBox.fromGeoPoints(roadTrip.places)
|
||||
val maxDistance = 7000000.0
|
||||
val logZoom = (defaultZoomLevel - minimumZoomLevel) * ln(boundingBox.diagonalLengthInMeters) / ln(maxDistance)
|
||||
val zoomLevel = (defaultZoomLevel - logZoom).coerceIn(minimumZoomLevel, defaultZoomLevel)
|
||||
return Pair(boundingBox.centerWithDateLine, zoomLevel)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
private const val ARG_PARAM1 = "param1"
|
||||
private const val ARG_PARAM2 = "param2"
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* Use the [List.newInstance] factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
class List : Fragment() {
|
||||
// TODO: Rename and change types of parameters
|
||||
private var param1: String? = null
|
||||
private var param2: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
param1 = it.getString(ARG_PARAM1)
|
||||
param2 = it.getString(ARG_PARAM2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_list, container, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param param1 Parameter 1.
|
||||
* @param param2 Parameter 2.
|
||||
* @return A new instance of fragment List.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
@JvmStatic
|
||||
fun newInstance(param1: String, param2: String) =
|
||||
List().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(ARG_PARAM1, param1)
|
||||
putString(ARG_PARAM2, param2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.LocationManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.MapView
|
||||
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
import android.location.LocationListener
|
||||
import android.util.Log
|
||||
import android.widget.ProgressBar
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import org.osmdroid.bonuspack.routing.OSRMRoadManager
|
||||
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
|
||||
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.ui.overlay.AddMarkerOverlay
|
||||
import uca.baptistearthur.geocaching.ui.overlay.MarkerOverlay
|
||||
import uca.baptistearthur.geocaching.ui.overlay.NewRoadtripOverlay
|
||||
import uca.baptistearthur.geocaching.ui.overlay.RecenterOverlay
|
||||
|
||||
class MyLocationMap : Map() {
|
||||
|
||||
private lateinit var spinner: ProgressBar
|
||||
private lateinit var locationManager: LocationManager
|
||||
private var isMapCentered = false;
|
||||
|
||||
private val locationListener = LocationListener { location ->
|
||||
val geoPoint = GeoPoint(location.latitude, location.longitude)
|
||||
if(!isMapCentered){
|
||||
map.controller.setCenter(geoPoint)
|
||||
spinner.visibility=View.GONE;
|
||||
isMapCentered=true;
|
||||
}
|
||||
map.invalidate()
|
||||
}
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){}
|
||||
|
||||
private fun displaySpinner(view: View){
|
||||
spinner = view.findViewById(R.id.mapLoading)
|
||||
spinner.visibility=View.VISIBLE
|
||||
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissionLauncher.launch(ACCESS_FINE_LOCATION)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addMapOverlays(mapView: MapView){
|
||||
super.addMapOverlays(mapView)
|
||||
Log.d("GeoMap", "MyLocationOverlay")
|
||||
|
||||
// Recenter Overlay
|
||||
val recenter = RecenterOverlay(GpsMyLocationProvider(context), map)
|
||||
recenter.enableMyLocation()
|
||||
map.overlays.add(recenter);
|
||||
|
||||
// My Location Overlay
|
||||
val myLocation = MyLocationNewOverlay(GpsMyLocationProvider(context), map)
|
||||
myLocation.enableMyLocation()
|
||||
map.overlays.add(myLocation)
|
||||
|
||||
// Add Marker Overlay
|
||||
val addMarker = AddMarkerOverlay(OSRMRoadManager(context, userAgent))
|
||||
map.overlays.add(addMarker);
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
Log.d("GeoMap", "MAP ON CREATE VIEW")
|
||||
val view = inflater.inflate(R.layout.fragment_map, container, false)
|
||||
map = view.findViewById(R.id.mapView)
|
||||
configureMap()
|
||||
displaySpinner(view)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Log.d("GeoMap", "MAP RESUME")
|
||||
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
Log.d("GeoMap", "MAP PAUSE")
|
||||
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
locationManager.removeUpdates(locationListener)
|
||||
isMapCentered=false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
private const val ARG_PARAM1 = "param1"
|
||||
private const val ARG_PARAM2 = "param2"
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* Use the [Profile.newInstance] factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
class Profile : Fragment() {
|
||||
// TODO: Rename and change types of parameters
|
||||
private var param1: String? = null
|
||||
private var param2: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
param1 = it.getString(ARG_PARAM1)
|
||||
param2 = it.getString(ARG_PARAM2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_profile, container, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param param1 Parameter 1.
|
||||
* @param param2 Parameter 2.
|
||||
* @return A new instance of fragment Profile.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
@JvmStatic
|
||||
fun newInstance(param1: String, param2: String) =
|
||||
Profile().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(ARG_PARAM1, param1)
|
||||
putString(ARG_PARAM2, param2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.application.RTApplication
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import uca.baptistearthur.geocaching.recyclerview.RoadTripAdapter
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModel
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModelFactory
|
||||
import java.util.*
|
||||
|
||||
class RoadTripFragment : Fragment() {
|
||||
private var roadTripRecyclerView : RecyclerView? = null
|
||||
|
||||
private val roadTripViewModel: RoadTripViewModel by viewModels<RoadTripViewModel> {
|
||||
RoadTripViewModelFactory((requireActivity().application as RTApplication).db.roadTripDAO())
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_roadtrip, container, false)
|
||||
|
||||
roadTripRecyclerView = view?.findViewById(R.id.recyclerViewRoadTripList)
|
||||
|
||||
roadTripViewModel.getAllRoadTrips().observe(viewLifecycleOwner, { roadTrips ->
|
||||
|
||||
if(roadTrips.isEmpty()){
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.noRoadTripFound,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}else roadTripRecyclerView?.adapter = RoadTripAdapter(roadTrips, findNavController())
|
||||
})
|
||||
|
||||
roadTripRecyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.util.Log
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.*
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.application.RTApplication
|
||||
import uca.baptistearthur.geocaching.converters.Converters
|
||||
import uca.baptistearthur.geocaching.converters.toFrenchFormat
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import uca.baptistearthur.geocaching.recyclerview.PlacesAdapter
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModel
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModelFactory
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
|
||||
class RoadtripDetail : Fragment() {
|
||||
|
||||
private var placesRecyclerView : RecyclerView? = null
|
||||
private val map: EditRoadtripMap = EditRoadtripMap()
|
||||
private lateinit var roadTrip: RoadTripEntity;
|
||||
private val roadTripViewModel: RoadTripViewModel by viewModels {
|
||||
RoadTripViewModelFactory((requireActivity().application as RTApplication).db.roadTripDAO())
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
// Inflate the layout for this fragment
|
||||
val view = inflater.inflate(R.layout.roadtrip_detail, container, false)
|
||||
roadTrip = Converters().toRoadTripEntity(arguments?.getString("roadTrip"))
|
||||
childFragmentManager.beginTransaction()
|
||||
.add(R.id.roadTripDetailMapView, map)
|
||||
.commit()
|
||||
|
||||
placesRecyclerView = view?.findViewById(R.id.recyclerViewPlacesList)
|
||||
placesRecyclerView?.adapter = PlacesAdapter(roadTrip.places)
|
||||
placesRecyclerView?.layoutManager = LinearLayoutManager(context)
|
||||
view?.findViewById<TextView>(R.id.roadTripDetailTitle)?.text = roadTrip.name
|
||||
view?.findViewById<TextView>(R.id.roadTripDetailDate)?.text = roadTrip.date.toFrenchFormat()
|
||||
|
||||
view?.findViewById<Button>(R.id.btnDeleteRoadTrip)?.setOnClickListener {
|
||||
try{
|
||||
roadTripViewModel.deleteRoadTrip(roadTrip)
|
||||
}catch (e: Exception){
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.roadTripDeleteError,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}finally {
|
||||
findNavController().popBackStack()
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.roadTripDeleteConfirmation,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
map.roadTrip=roadTrip
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import org.osmdroid.bonuspack.routing.RoadManager
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
class AddMarkerOverlay(roadManager: RoadManager) : MarkerOverlay<NewRoadtripOverlay>(roadManager) {
|
||||
override fun createNewConfirmationOverlay(): NewRoadtripOverlay = NewRoadtripOverlay(places)
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.osmdroid.views.MapView
|
||||
import org.osmdroid.views.overlay.Overlay
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
abstract class ConfirmationOverlay(val points: MutableCollection<PlaceMarker>) : Overlay() {
|
||||
|
||||
private var circleRectF=RectF()
|
||||
|
||||
override fun draw(canvas: Canvas, mapView: MapView, shadow: Boolean) {
|
||||
|
||||
val circleSize = 300f
|
||||
val circlePadding = 20f
|
||||
val circleY = canvas.height - circleSize - circlePadding
|
||||
circleRectF= RectF(circlePadding, circleY, circlePadding + circleSize, circleY + circleSize)
|
||||
|
||||
val paint = Paint().apply {
|
||||
color = Color.WHITE
|
||||
style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
canvas.drawCircle(
|
||||
circleSize / 2 + circlePadding,
|
||||
circleY + circleSize / 2,
|
||||
circleSize / 2,
|
||||
paint
|
||||
)
|
||||
|
||||
val iconSize = 180
|
||||
val icon = ContextCompat.getDrawable(mapView.context, R.drawable.check)
|
||||
|
||||
val iconX = (circleSize / 2 - iconSize / 2 + circlePadding).toInt()
|
||||
val iconY = (circleY + circleSize / 2 - iconSize / 2).toInt()
|
||||
|
||||
icon?.setBounds(iconX, iconY, iconX + iconSize, iconY + iconSize)
|
||||
icon?.draw(canvas)
|
||||
}
|
||||
|
||||
override fun onSingleTapConfirmed(e: MotionEvent?, mapView: MapView?) =
|
||||
if (e != null && circleRectF.contains(e.x, e.y)) {
|
||||
mapView?.let{
|
||||
confirm(it)
|
||||
}
|
||||
true
|
||||
}else{
|
||||
false
|
||||
}
|
||||
|
||||
abstract fun confirm(mapView: MapView)
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.graphics.Canvas
|
||||
import org.osmdroid.bonuspack.routing.RoadManager
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.MapView
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
class EditMarkerOverlay(roadManager: RoadManager, var roadTrip: RoadTripEntity) : MarkerOverlay<EditRoadtripOverlay>(roadManager) {
|
||||
|
||||
fun addPlaces(geopoints: Collection<GeoPoint>, mapView: MapView)=
|
||||
geopoints.forEach {
|
||||
addMarkerAtGeopoint(it, mapView)
|
||||
}
|
||||
|
||||
override fun createNewConfirmationOverlay(): EditRoadtripOverlay = EditRoadtripOverlay(places, roadTrip)
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.text.InputFilter
|
||||
import android.util.Log
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.MapView
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.application.RTApplication
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModel
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModelFactory
|
||||
import java.util.*
|
||||
|
||||
class EditRoadtripOverlay(points: MutableCollection<PlaceMarker>, val roadTripEntity: RoadTripEntity) : ConfirmationOverlay(points) {
|
||||
|
||||
fun getRoadTripViewModelFromOverlay(overlayContext: Context): RoadTripViewModel {
|
||||
val roadTripDao = (overlayContext.applicationContext as RTApplication).db.roadTripDAO()
|
||||
val viewModelFactory = RoadTripViewModelFactory(roadTripDao)
|
||||
return ViewModelProvider(overlayContext as ViewModelStoreOwner, viewModelFactory).get(
|
||||
RoadTripViewModel::class.java)
|
||||
}
|
||||
|
||||
private fun onValidation(mapView: MapView, input: String) {
|
||||
val places: MutableList<Place> =
|
||||
points.map { Place(it.position.latitude, it.position.longitude) }.toMutableList()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
places.filter { it.address.displayName === "unknown" }.forEach { it.initAddress() }
|
||||
val newRoadTrip = RoadTripEntity(
|
||||
id = roadTripEntity.id,
|
||||
name = input,
|
||||
date = roadTripEntity.date,
|
||||
places = places
|
||||
)
|
||||
getRoadTripViewModelFromOverlay(mapView.context).deleteRoadTrip(roadTripEntity)
|
||||
getRoadTripViewModelFromOverlay(mapView.context).insertRoadTrip(newRoadTrip)
|
||||
Toast.makeText(
|
||||
mapView.context,
|
||||
R.string.changesSaved,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun confirm(mapView: MapView) {
|
||||
val input = EditText(mapView.context)
|
||||
input.setText(roadTripEntity.name)
|
||||
input.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(50))
|
||||
|
||||
val dialog = AlertDialog.Builder(mapView.context)
|
||||
.setTitle(R.string.newRoadtripDialog)
|
||||
.setView(input)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
val userInput = input.text.toString()
|
||||
if (userInput.isNotBlank()) {
|
||||
onValidation(mapView, input.text.toString())
|
||||
} else {
|
||||
Toast.makeText(
|
||||
mapView.context,
|
||||
R.string.emptyTextError,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.create()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.content.Context
|
||||
import android.view.MotionEvent
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.osmdroid.bonuspack.routing.RoadManager
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.MapView
|
||||
import org.osmdroid.views.overlay.Overlay
|
||||
import org.osmdroid.views.overlay.Polyline
|
||||
import uca.baptistearthur.geocaching.R
|
||||
|
||||
|
||||
abstract class MarkerOverlay<T : ConfirmationOverlay>(val roadManager: RoadManager) : Overlay() {
|
||||
|
||||
protected var places: MutableSet<PlaceMarker> = mutableSetOf()
|
||||
private lateinit var roadOverlay: Polyline
|
||||
private var confirmationOverlayIsVisible = false;
|
||||
|
||||
protected fun addMarkerAtGeopoint(geoPoint: GeoPoint, mapView: MapView){
|
||||
val marker = PlaceMarker(mapView, this)
|
||||
marker.position = geoPoint
|
||||
if(places.isNotEmpty()) places.last().setDefaultIcon()
|
||||
places.add(marker)
|
||||
places.forEach{ it.closeInfoWindow()}
|
||||
computeIcons(mapView.context)
|
||||
mapView.overlays.add(marker)
|
||||
computeRoad(mapView)
|
||||
computeConfirmationOverlay(mapView);
|
||||
mapView.invalidate()
|
||||
}
|
||||
|
||||
override fun onDoubleTap(e: MotionEvent?, mapView: MapView?): Boolean {
|
||||
|
||||
val proj = mapView?.projection;
|
||||
if(proj!=null){
|
||||
val geoPoint = proj.fromPixels(e?.x?.toInt()!!, e.y.toInt() ) as GeoPoint
|
||||
addMarkerAtGeopoint(geoPoint, mapView)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fun computeIcons(context: Context) {
|
||||
if (places.isNotEmpty()) {
|
||||
val flagIcon = ContextCompat.getDrawable(context, R.drawable.roadtrip_marker)!!
|
||||
places.last().icon = flagIcon
|
||||
places.first().icon = flagIcon
|
||||
}
|
||||
}
|
||||
|
||||
fun computeRoad(mapView: MapView) {
|
||||
mapView.overlays.removeAll{ it is Polyline }
|
||||
if (places.size > 1) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val road = roadManager.getRoad(ArrayList(places.map{it.position}))
|
||||
withContext(Dispatchers.Main) {
|
||||
roadOverlay = RoadManager.buildRoadOverlay(road)
|
||||
mapView.overlays.add(roadOverlay)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun createNewConfirmationOverlay(): T
|
||||
|
||||
fun computeConfirmationOverlay(mapView: MapView){
|
||||
if (places.size > 1) {
|
||||
if(!confirmationOverlayIsVisible) {
|
||||
mapView.overlays.add(createNewConfirmationOverlay())
|
||||
confirmationOverlayIsVisible = true
|
||||
}
|
||||
}else{
|
||||
mapView.overlays.removeAll{ it is ConfirmationOverlay }
|
||||
confirmationOverlayIsVisible=false
|
||||
}
|
||||
}
|
||||
fun removeMarker(placeMarker: PlaceMarker) = places.remove(placeMarker);
|
||||
fun getMarkerLabel(placeMarker: PlaceMarker) =
|
||||
when (placeMarker) {
|
||||
places.first() -> {
|
||||
"Start"
|
||||
}
|
||||
places.last() -> {
|
||||
"Finish"
|
||||
}
|
||||
else -> {
|
||||
"Step " + places.indexOf(placeMarker);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.text.InputFilter
|
||||
import android.util.Log
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
import org.osmdroid.views.MapView
|
||||
import org.osmdroid.views.overlay.Polyline
|
||||
import uca.baptistearthur.geocaching.R
|
||||
import uca.baptistearthur.geocaching.application.RTApplication
|
||||
import uca.baptistearthur.geocaching.model.Address
|
||||
import uca.baptistearthur.geocaching.model.Place
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModel
|
||||
import uca.baptistearthur.geocaching.viewModels.RoadTripViewModelFactory
|
||||
import java.util.*
|
||||
|
||||
|
||||
class NewRoadtripOverlay(points: MutableCollection<PlaceMarker>) : ConfirmationOverlay(points) {
|
||||
|
||||
fun getRoadTripViewModelFromOverlay(overlayContext: Context): RoadTripViewModel {
|
||||
val roadTripDao = (overlayContext.applicationContext as RTApplication).db.roadTripDAO()
|
||||
val viewModelFactory = RoadTripViewModelFactory(roadTripDao)
|
||||
return ViewModelProvider(overlayContext as ViewModelStoreOwner, viewModelFactory).get(RoadTripViewModel::class.java)
|
||||
}
|
||||
|
||||
private fun clearMap(mapView: MapView){
|
||||
mapView.overlays.removeAll { it is PlaceMarker || it is Polyline || it is NewRoadtripOverlay }
|
||||
}
|
||||
|
||||
private fun onValidation(mapView: MapView, input: String){
|
||||
val places: MutableList<Place> = points.map { Place(it.position.latitude, it.position.longitude) }.toMutableList()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
places.forEach{
|
||||
it.initAddress()
|
||||
Log.d("GeoMap", it.address.displayName)
|
||||
}
|
||||
val newRoadTrip = RoadTripEntity(
|
||||
id = 0, // auto-generated ID
|
||||
name = input,
|
||||
date = Date(),
|
||||
places = places
|
||||
)
|
||||
getRoadTripViewModelFromOverlay(mapView.context).insertRoadTrip(newRoadTrip);
|
||||
Toast.makeText(
|
||||
mapView.context,
|
||||
R.string.roadtripAdded,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
points.clear()
|
||||
}
|
||||
clearMap(mapView)
|
||||
}
|
||||
|
||||
override fun confirm(mapView: MapView){
|
||||
val input = EditText(mapView.context)
|
||||
input.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(50))
|
||||
|
||||
val dialog = AlertDialog.Builder(mapView.context)
|
||||
.setTitle(R.string.newRoadtripDialog)
|
||||
.setView(input)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
val userInput = input.text.toString()
|
||||
if (userInput.isNotBlank()) {
|
||||
onValidation(mapView, input.text.toString())
|
||||
} else {
|
||||
Toast.makeText(
|
||||
mapView.context,
|
||||
R.string.emptyTextError,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.create()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.ui.overlay
|
||||
|
||||
import android.view.MotionEvent
|
||||
import org.osmdroid.views.MapView
|
||||
import org.osmdroid.views.overlay.Marker
|
||||
|
||||
class PlaceMarker(val mapView: MapView, val parent : MarkerOverlay<*>) : Marker(mapView) {
|
||||
|
||||
override fun getTitle() = parent.getMarkerLabel(this)
|
||||
override fun onLongPress(e: MotionEvent?, mapView: MapView?): Boolean {
|
||||
if(mapView!=null && this.hitTest(e, mapView)) {
|
||||
parent.removeMarker(this)
|
||||
this.closeInfoWindow()
|
||||
mapView.overlays.remove(this)
|
||||
parent.computeIcons(mapView.context)
|
||||
parent.computeRoad(mapView)
|
||||
parent.computeConfirmationOverlay(mapView)
|
||||
mapView.invalidate()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.viewModels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
//import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
import uca.baptistearthur.geocaching.data.RoadTripDAO
|
||||
import uca.baptistearthur.geocaching.model.RoadTripEntity
|
||||
|
||||
class RoadTripViewModel(val dao: RoadTripDAO): ViewModel() {
|
||||
|
||||
fun getRoadTripById(id: Int) = dao.getRoadTripById(id).asLiveData()
|
||||
|
||||
fun getAllRoadTrips() = dao.getAllRoadTrips().asLiveData()
|
||||
|
||||
fun insertRoadTrip(r: RoadTripEntity){
|
||||
viewModelScope.launch {
|
||||
dao.insertRoadTrip(r)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteRoadTrip(r: RoadTripEntity){
|
||||
viewModelScope.launch {
|
||||
dao.deleteRoadTrip(r)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package uca.baptistearthur.geocaching.viewModels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import uca.baptistearthur.geocaching.data.RoadTripDAO
|
||||
|
||||
class RoadTripViewModelFactory(private val dao: RoadTripDAO): ViewModelProvider.Factory{
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(RoadTripViewModel::class.java)){
|
||||
return RoadTripViewModel(dao) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@ -1,15 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="0.4698"
|
||||
android:scaleY="0.4698"
|
||||
android:translateX="6.3624"
|
||||
android:translateY="6.3624">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M22,16v-2l-8.5,-5V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5V9L2,14v2l8.5,-2.5V19L8,20.5L8,22l4,-1l4,1l0,-1.5L13.5,19v-5.5L22,16z"/>
|
||||
</group>
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:gravity="bottom">
|
||||
<shape>
|
||||
<size android:height="1dp" />
|
||||
<solid android:color="@color/main_turquoise_200" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
@ -1,5 +0,0 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
@ -1,20 +0,0 @@
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<solid
|
||||
android:color="@color/gray" >
|
||||
</solid>
|
||||
|
||||
<padding
|
||||
android:left="5dp"
|
||||
android:top="5dp"
|
||||
android:right="5dp"
|
||||
android:bottom="5dp" >
|
||||
</padding>
|
||||
|
||||
<corners
|
||||
android:radius="11dp" >
|
||||
</corners>
|
||||
|
||||
</shape>
|
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||
</vector>
|
@ -1,5 +0,0 @@
|
||||
<vector android:height="50dp" android:tint="#FF0000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="50dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z"/>
|
||||
</vector>
|
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Button
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/btnGetRoadTripsInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:layout_gravity="start"
|
||||
android:gravity="left"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
tools:ignore="RtlHardcoded"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@drawable/bottom_border"
|
||||
/>
|
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_margin="5dp"
|
||||
android:background="@drawable/corner_radius"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/placeImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginLeft="7dp"
|
||||
android:layout_margin="7dp"
|
||||
android:src="@drawable/center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtPlaceAddress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="15dp"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginRight="2dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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"
|
||||
tools:context=".ui.fragment.List">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="List" />
|
||||
|
||||
</FrameLayout>
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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"
|
||||
tools:context=".ui.fragment.Profile">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="PROFILE" />
|
||||
|
||||
</FrameLayout>
|
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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"
|
||||
tools:context=".ui.fragment.RoadTripFragment"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/roadtrip_title"
|
||||
android:background="@color/main_turquoise_500"
|
||||
android:textColor="@color/main_turquoise_50"
|
||||
android:padding="10dp"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerViewRoadTripList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragment.RoadtripDetail"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roadTripDetailTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TMP/ Roadtrip Name"
|
||||
android:background="@color/main_turquoise_500"
|
||||
android:textColor="@color/main_turquoise_50"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="20sp"
|
||||
android:paddingStart="10dp"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roadTripDetailDate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TMP/ Date"
|
||||
android:background="@color/main_turquoise_500"
|
||||
android:textColor="@color/main_turquoise_50"
|
||||
android:textSize="15sp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="5dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/roadTripDetailMapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/corner_radius"
|
||||
android:layout_margin="5dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/placesList"
|
||||
android:textColor="@color/main_turquoise_200"
|
||||
android:padding="5dp"
|
||||
android:textSize="17sp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerViewPlacesList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnDeleteRoadTrip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btnDeleteRoadTrip"
|
||||
android:backgroundTint="@color/main_turquoise_200"
|
||||
android:layout_margin="10dp"/>
|
||||
|
||||
</LinearLayout>
|
@ -1,13 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/profile"
|
||||
android:enabled="true"
|
||||
android:title="@string/profil"
|
||||
android:icon="@drawable/profile"/>
|
||||
<item
|
||||
android:id="@+id/map"
|
||||
android:enabled="true"
|
||||
android:title="@string/map"
|
||||
android:title="@string/carte"
|
||||
android:icon="@drawable/map"/>
|
||||
<item
|
||||
android:id="@+id/roadTrip"
|
||||
android:id="@+id/list"
|
||||
android:enabled="true"
|
||||
android:title="@string/travels"
|
||||
android:icon="@drawable/road_trip" />
|
||||
android:title="@string/liste"
|
||||
android:icon="@drawable/list" />
|
||||
</menu>
|
||||
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/app_logo_background"/>
|
||||
<foreground android:drawable="@drawable/app_logo_foreground"/>
|
||||
</adaptive-icon>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/app_logo_background"/>
|
||||
<foreground android:drawable="@drawable/app_logo_foreground"/>
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 982 B |
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 7.6 KiB |
@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/navgraph"
|
||||
app:startDestination="@id/map">
|
||||
<fragment
|
||||
android:id="@+id/roadTrip"
|
||||
android:name="uca.baptistearthur.geocaching.ui.fragment.RoadTripFragment"
|
||||
android:label="fragment_roadtrip"
|
||||
tools:layout="@layout/fragment_roadtrip" >
|
||||
<action
|
||||
android:id="@+id/action_roadTripFragment_to_roadtripDetail"
|
||||
app:destination="@id/roadtripDetail"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/roadtripDetail"
|
||||
android:name="uca.baptistearthur.geocaching.ui.fragment.RoadtripDetail"
|
||||
android:label="roadtrip_detail"
|
||||
tools:layout="@layout/roadtrip_detail" />
|
||||
<fragment
|
||||
android:id="@+id/map"
|
||||
android:name="uca.baptistearthur.geocaching.ui.fragment.MyLocationMap"
|
||||
android:label="fragment_map"
|
||||
tools:layout="@layout/fragment_map" />
|
||||
<fragment android:id="@+id/placeholder" >
|
||||
<action
|
||||
android:id="@+id/action_placeholder_to_map2"
|
||||
app:destination="@id/roadTripDetailMapView" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/roadTripDetailMapView"
|
||||
android:name="uca.baptistearthur.geocaching.ui.fragment.EditRoadtripMap"
|
||||
android:label="Map" />
|
||||
</navigation>
|
@ -1,18 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">RoadTrip</string>
|
||||
<string name="map">Carte</string>
|
||||
<string name="travels">Voyages</string>
|
||||
<string name="roadtrip_title">Mes RoadTrips:</string>
|
||||
<string name="add_roadtrip_button">+</string>
|
||||
<string name="placesList">Vos lieux à visiter:</string>
|
||||
<string name="btnDeleteRoadTrip">Supprimer le voyage</string>
|
||||
<string name="confirm">Valider</string>
|
||||
<string name="cancel">Annuler</string>
|
||||
<string name="emptyTextError">Le texte ne peux pas être vide</string>
|
||||
<string name="newRoadtripDialog">Entrez le nom de votre voyage</string>
|
||||
<string name="roadTripDeleteConfirmation">Le voyage a bien été supprimé</string>
|
||||
<string name="roadTripDeleteError">Une erreur est survenue lors de la suppresion du voyage</string>
|
||||
<string name="noRoadTripFound">Aucun voyage n\'a été trouvé, utilisez la carte</string>
|
||||
<string name="roadtripAdded">Roadtrip ajouté</string>
|
||||
<string name="changesSaved">Changements sauvegardés</string>
|
||||
</resources>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="app_logo_background">#52796F</color>
|
||||
</resources>
|
@ -1,18 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">RoadTrip</string>
|
||||
<string name="map">Map</string>
|
||||
<string name="travels">Travels</string>
|
||||
<string name="roadtrip_title">My RoadTrips:</string>
|
||||
<string name="add_roadtrip_button">+</string>
|
||||
<string name="placesList">Your places to visit:</string>
|
||||
<string name="btnDeleteRoadTrip">Delete travel</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="emptyTextError">The text cannot be empty</string>
|
||||
<string name="newRoadtripDialog">Enter the name of your travel</string>
|
||||
<string name="roadTripDeleteConfirmation">The road trip has been successfully deleted</string>
|
||||
<string name="roadTripDeleteError">An error occurred while deleting the road trip.</string>
|
||||
<string name="noRoadTripFound">No trip was found, add one with the map.</string>
|
||||
<string name="roadtripAdded">Roadtrip added</string>
|
||||
<string name="changesSaved">Changes saved</string>
|
||||
<string name="app_name">Geocaching</string>
|
||||
<string name="profil">Profil</string>
|
||||
<string name="carte">Carte</string>
|
||||
<string name="liste">Liste</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
@ -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.4.1' apply false
|
||||
id 'com.android.library' version '7.4.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
|
||||
// id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false
|
||||
id 'com.android.application' version '7.3.0' apply false
|
||||
id 'com.android.library' version '7.3.0' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
|
||||
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#Fri Mar 03 14:28:35 CET 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|