Compare commits

..

9 Commits

@ -9,7 +9,7 @@ android {
defaultConfig {
applicationId "fr.iut.cinecool"
minSdk 19
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
@ -36,20 +36,16 @@ android {
}
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation 'androidx.fragment:fragment-ktx:1.5.6'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'androidx.core:core-ktx:+'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
@ -71,17 +67,17 @@ dependencies {
// Jetpack Compose Integration
implementation("androidx.navigation:navigation-compose:2.5.3")
// Map
implementation 'org.osmdroid:osmdroid-android:6.1.10'
implementation 'com.github.MKergall:osmbonuspack:6.6.0'
// API
implementation "com.squareup.okhttp3:okhttp:4.9.3"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
implementation "com.google.code.gson:gson:2.8.9"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'androidx.fragment:fragment-ktx:1.5.6'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}

@ -1,27 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Ajoutez cette ligne pour autoriser l'accès à la localisation -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- Ajoutez cette ligne pour autoriser l'accès à Internet -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="org.osmdroid.config"
android:resource="@xml/osmdroid_config" />
<activity android:name="MainActivity">
android:theme="@style/Theme.CineCool"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/title_activity_main"
android:theme="@style/Theme.CineCool.NoActionBar"
tools:ignore="DuplicateActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

@ -0,0 +1,25 @@
package fr.iut.cinecool.API.OSM
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object ApiClientOSM {
private const val OSM_BASE_URL = "https://nominatim.openstreetmap.org/"
private const val ORS_BASE_URL = "https://api.openrouteservice.org/"
fun getOSMClient(): ApiService {
return Retrofit.Builder()
.baseUrl(OSM_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
fun getORSClient(): ApiService {
return Retrofit.Builder()
.baseUrl(ORS_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}

@ -0,0 +1,22 @@
package fr.iut.cinecool.API.OSM
import fr.iut.cinecool.model.CinemaResult
import fr.iut.cinecool.model.RouteResult
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface ApiService {
@GET("search")
fun searchCinemas(
@Query("q") query: String,
@Query("format") format: String = "json"
): Call<List<CinemaResult>>
@GET("v2/directions/driving-car")
fun getRoute(
@Query("api_key") apiKey: String,
@Query("start") start: String,
@Query("end") end: String
): Call<RouteResult>
}

@ -0,0 +1,47 @@
package fr.iut.cinecool.API.OSM
import fr.iut.cinecool.model.CinemaResult
import fr.iut.cinecool.model.RouteResult
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MethodApiOSM {
fun searchCinemas(latitude: Double, longitude: Double) {
val apiService = ApiClientOSM.getOSMClient()
val call = apiService.searchCinemas("cinema near $latitude,$longitude")
call.enqueue(object : Callback<List<CinemaResult>> {
override fun onResponse(call: Call<List<CinemaResult>>, response: Response<List<CinemaResult>>) {
val cinemas = response.body()
// Trouvez le cinéma le plus proche ou affichez la liste des cinémas
// Puis, utilisez la fonction getRoute() pour obtenir l'itinéraire
}
override fun onFailure(call: Call<List<CinemaResult>>, t: Throwable) {
// Gérer l'échec
}
})
}
fun getRoute(startLat: Double, startLon: Double, endLat: Double, endLon: Double) {
val apiKey = "5b3ce3597851110001cf6248953315121da3401d85fa50fce9c0991e"
val apiService = ApiClientOSM.getORSClient()
val call = apiService.getRoute(apiKey, "$startLat,$startLon", "$endLat,$endLon")
call.enqueue(object : Callback<RouteResult> {
override fun onResponse(call: Call<RouteResult>, response: Response<RouteResult>) {
val routeResult = response.body()
val steps = routeResult?.routes?.get(0)?.segments?.get(0)?.steps
if (steps != null) {
// Utilisez les instructions de l'itinéraire pour guider l'utilisateur
} else {
// Gérer le cas où il n'y a pas d'itinéraire disponible
}
}
override fun onFailure(call: Call<RouteResult>, t: Throwable) {
// Gérer l'échec
}
})
}
}

@ -1,16 +0,0 @@
package fr.iut.cinecool.API.OpenStreetMap
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Query
interface ApiService {
@Headers("User-Agent: MyApp")
@GET("search")
fun searchCinemas(
@Query("q") query: String,
@Query("format") format: String = "json",
@Query("limit") limit: Int = 10
): Call<List<Cinema>>
}

@ -1,17 +0,0 @@
package fr.iut.cinecool.API.OpenStreetMap
import com.google.gson.annotations.SerializedName
data class Cinema(
@SerializedName("place_id")
val placeId: Long,
@SerializedName("lat")
val latitude: Double,
@SerializedName("lon")
val longitude: Double,
@SerializedName("display_name")
val displayName: String
)

@ -1,34 +0,0 @@
package fr.iut.cinecool.API.OpenStreetMap
import android.location.Location
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class Repository {
private fun fetchNearbyCinemas(location: Location) {
val retrofit = Retrofit.Builder()
.baseUrl("https://nominatim.openstreetmap.org/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val nominatimService = retrofit.create(NominatimService::class.java)
val call = nominatimService.searchCinemas("cinema near ${location.latitude},${location.longitude}")
call.enqueue(object : Callback<List<Cinema>> {
override fun onResponse(call: Call<List<Cinema>>, response: Response<List<Cinema>>) {
if (response.isSuccessful) {
val cinemas = response.body() ?: emptyList()
displayCinemas(cinemas)
}
}
override fun onFailure(call: Call<List<Cinema>>, t: Throwable) {
// Gérer l'erreur
}
})
}
}

@ -3,7 +3,7 @@ package fr.iut.cinecool.API.THMDB
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object ApiClient {
object ApiClientTHMDB {
private const val BASE_URL = "https://api.themoviedb.org/3/"
private val retrofit: Retrofit = Retrofit.Builder()

@ -1,7 +1,7 @@
package fr.iut.cinecool.API.THMDB
class Repository {
private val apiService = ApiClient.apiService
class MethodApiTHMDB {
private val apiService = ApiClientTHMDB.apiService
suspend fun getPopularMovies(apiKey: String, page: Int): MovieResponse {
return apiService.getPopularMovies(apiKey, page)

@ -1,47 +0,0 @@
package fr.iut.cinecool.API.THMDB
import android.os.Parcel
import android.os.Parcelable
data class MovieResponse(
val page: Int,
val results: List<Movie>,
val total_pages: Int,
val total_results: Int
)
data class Movie(
val id: Int,
val title: String,
val poster_path: String?,
val overview: String
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString()!!,
parcel.readString(),
parcel.readString()!!
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(title)
parcel.writeString(poster_path)
parcel.writeString(overview)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Movie> {
override fun createFromParcel(parcel: Parcel): Movie {
return Movie(parcel)
}
override fun newArray(size: Int): Array<Movie?> {
return arrayOfNulls(size)
}
}
}

@ -1,18 +0,0 @@
package fr.iut.cinecool
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
class CinemaActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cinema)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
navController = navHostFragment.navController
}
}

@ -1,61 +1,43 @@
package fr.iut.cinecool
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import fr.iut.cinecool.fragments.CinemaListFragment
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import android.Manifest
class MainActivity : AppCompatActivity() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private val locationPermissionRequestCode = 1
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, CinemaListFragment())
.commit()
}
requestLocationPermission()
setContentView(R.layout.activity_master)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
navController = navHostFragment.navController
}
private fun requestLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
locationPermissionRequestCode
)
private val REQUEST_LOCATION_PERMISSION = 1
private fun checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION)
} else {
// Appeler searchCinemas() avec les coordonnées de l'utilisateur
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == locationPermissionRequestCode) {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// La permission de localisation a été accordée, vous pouvez effectuer les actions correspondantes
// Appeler searchCinemas() avec les coordonnées de l'utilisateur
} else {
// La permission de localisation a été refusée, vous devez gérer ce cas
// Gérer le cas où la permission est refusée
}
}
}
}
}

@ -1,43 +0,0 @@
package fr.iut.cinecool.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import fr.iut.cinecool.API.OpenStreetMap.Cinema
import fr.iut.cinecool.R
class CinemaAdapter(private val onCinemaClickListener: (Cinema) -> Unit) :
RecyclerView.Adapter<CinemaAdapter.CinemaViewHolder>() {
private val cinemas = mutableListOf<Cinema>()
fun updateCinemas(newCinemas: List<Cinema>) {
cinemas.clear()
cinemas.addAll(newCinemas)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CinemaViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_cinema, parent, false)
return CinemaViewHolder(itemView, onCinemaClickListener)
}
override fun onBindViewHolder(holder: CinemaViewHolder, position: Int) {
holder.bind(cinemas[position])
}
override fun getItemCount(): Int = cinemas.size
class CinemaViewHolder(itemView: View, private val onCinemaClickListener: (Cinema) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private val cinemaNameTextView: TextView = itemView.findViewById(R.id.cinemaNameTextView)
fun bind(cinema: Cinema) {
cinemaNameTextView.text = cinema.displayName
itemView.setOnClickListener { onCinemaClickListener(cinema) }
}
}
}

@ -10,31 +10,45 @@ import com.bumptech.glide.Glide
import fr.iut.cinecool.R
import fr.iut.cinecool.API.THMDB.Movie
class MovieAdapter : RecyclerView.Adapter<MovieAdapter.MovieViewHolder>() {
private var movies: List<Movie> = emptyList()
class MovieAdapter(private var moviesList: List<Movie>) :
RecyclerView.Adapter<MovieAdapter.MovieViewHolder>() {
var onItemClick : ((Movie)->Unit)?=null
class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView = itemView.findViewById<ImageView>(R.id.imageView)
val MovieName = itemView.findViewById<TextView>(R.id.MovieName)
val OtherInformations = itemView.findViewById<TextView>(R.id.OtherInformations)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.movie_item, parent, false)
val view = LayoutInflater.from(parent.context).inflate(R.layout.movie, parent, false)
return MovieViewHolder(view)
}
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
holder.bind(movies[position])
override fun getItemCount(): Int {
return moviesList.size
}
override fun getItemCount(): Int = movies.size
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
val movie = moviesList[position]
val imageUrl = "https://image.tmdb.org/t/p/w500${movie.poster_path}"
Glide.with(holder.itemView.context)
.load(imageUrl)
.placeholder(R.drawable.no_pictures)
.into(holder.imageView)
holder.MovieName.text = movie.title
holder.OtherInformations.text = movie.overview
holder.itemView.setOnClickListener {
onItemClick?.invoke(movie)
}
fun setMovies(movies: List<Movie>) {
this.movies = movies
notifyDataSetChanged()
// Pour cet exemple, je mets l'overview en tant qu'OtherInformations, vous pouvez le personnaliser selon vos besoins
}
class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val titleTextView: TextView = itemView.findViewById(R.id.titleTextView)
fun bind(movie: Movie) {
titleTextView.text = movie.title
}
// Ajoutez cette méthode pour mettre à jour la liste des films
fun updateMovies(newMovies: List<Movie>) {
moviesList = newMovies
notifyDataSetChanged()
}
}

@ -1,57 +0,0 @@
package fr.iut.cinecool.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import fr.iut.cinecool.API.OpenStreetMap.Cinema
import fr.iut.cinecool.R
import fr.iut.cinecool.adapter.MovieAdapter
class CinemaDetailFragment : Fragment() {
private lateinit var cinemaNameTextView: TextView
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: MovieAdapter
private lateinit var cinema: Cinema
companion object {
private const val ARG_CINEMA = "cinema"
fun newInstance(cinema: Cinema): CinemaDetailFragment {
val fragment = CinemaDetailFragment()
val args = Bundle()
args.putParcelable(ARG_CINEMA, cinema)
fragment.arguments = args
return fragment
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
cinema = arguments?.getParcelable(ARG_CINEMA) ?: throw IllegalStateException("Cinema not provided")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_cinema_detail, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cinemaNameTextView = view.findViewById(R.id.cinemaNameTextView)
recyclerView = view.findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
adapter = MovieAdapter()
recyclerView.adapter = adapter
cinemaNameTextView.text = cinema.displayName
// Récupérez et affichez la liste des films à l'affiche pour le cinéma sélectionné
}
}

@ -1,19 +0,0 @@
package fr.iut.cinecool.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import fr.iut.cinecool.R
class CinemaFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_cinema, container, false)
}
}

@ -1,45 +0,0 @@
package fr.iut.cinecool.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import fr.iut.cinecool.R
import fr.iut.cinecool.adapter.CinemaAdapter
class CinemaListFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: CinemaAdapter
private lateinit var fusedLocationClient: FusedLocationProviderClient
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_cinema_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
adapter = CinemaAdapter { cinema ->
val fragment = CinemaDetailFragment.newInstance(cinema)
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit()
}
recyclerView.adapter = adapter
fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
// Récupérez la position de l'utilisateur et affichez les cinémas à proximité
}
}

@ -0,0 +1,45 @@
package fr.iut.cinecool.fragments
import android.content.Context.LOCATION_SERVICE
import android.location.LocationManager
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import androidx.core.content.ContextCompat.getSystemService
import androidx.navigation.fragment.findNavController
import fr.iut.cinecool.R
import fr.iut.cinecool.databinding.FragmentLoginBinding
import fr.iut.cinecool.databinding.FragmentMoviesBinding
class LoginFragment : Fragment() {
private var locationManager : LocationManager? = null
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//locationManager = this.context?.let { getSystemService(it,LOCATION_SERVICE) } as LocationManager?
super.onViewCreated(view, savedInstanceState)
val loginButton = view.findViewById<ImageView>(R.id.loginButton)
loginButton.setOnClickListener(){
login()
}
}
fun login(){
val name = view?.findViewById<EditText>(R.id.name)?.text
if (name != null) {
findNavController().navigate(R.id.login_to_movies)
}
}
}

@ -1,45 +0,0 @@
package fr.iut.cinecool.fragments
import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
//import androidx.lifecycle.viewmodel.CreationExtras.Empty.map
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
class MapFragment : Fragment() {
/*
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_map)
map = findViewById(R.id.map)
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)
mapFragment.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
this.gMap = googleMap
val mapIndia = LatLng(20.5937, 789629)
this.gMap.addMarker(MarkerOptions().position(mapIndia).title("Marker in India"))
this.gMap.moveCamera(CameraUpdateFactory.newLatLng(mapIndia))
}
override fun onDestroyView() {
super.onDestroyView()
}
// TODO https://youtu.be/JzxjNNCYt_o
// https://console.cloud.google.com/apis/credentials?hl=fr&project=upbeat-grammar-382309
*/
}

@ -1,47 +1,51 @@
package fr.iut.cinecool.fragments
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import androidx.fragment.app.Fragment
// import fr.iut.cinecool.databinding.FragmentMovieDetailBinding
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import fr.iut.cinecool.R
import fr.iut.cinecool.viewModel.cineViewModel
class MovieDetailFragment : Fragment() {
/*private var _binding: FragmentDetailMovieBinding? = null
private val binding get() = _binding!!
private val sharedViewModel: cineViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDetailMovieBinding.inflate(inflater, container, false)
return binding.root
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_detail, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Récupérez le film passé en argument
val movie: Movie? = arguments?.getParcelable("movie")
// Mettez à jour les vues avec les données du film
if (movie != null) {
binding.titreFilm.text = movie.title
binding.description.text = movie.overview
val imageUrl = "https://image.tmdb.org/t/p/w500${movie.poster_path}"
Glide.with(binding.afficheFilm.context)
.load(imageUrl)
.placeholder(R.drawable.imitation_game)
.into(binding.afficheFilm)
}
// Gérer le clic sur le bouton de retour
binding.backButton.setOnClickListener {
findNavController().popBackStack()
init()
val button = view.findViewById<ImageButton>(R.id.returnButton)
button.setOnClickListener {
findNavController().navigate(R.id.action_SessionFragment_to_fragment_movies)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}*/
private fun init() {
requireView().findViewById<TextView>(R.id.title).text= sharedViewModel.cine.value?.title
val desc = requireView().findViewById<TextView>(R.id.description)
desc.text=sharedViewModel.cine.value?.overview
desc.isScrollContainer = true
desc.movementMethod = ScrollingMovementMethod()
val img=requireView().findViewById<ImageView>(R.id.afficheFilm)
val imageUrl = "https://image.tmdb.org/t/p/w500${sharedViewModel.cine.value?.poster_path}"
Glide.with(this.requireContext())
.load(imageUrl)
.placeholder(R.drawable.no_pictures)
.into(img)
}
}

@ -13,7 +13,7 @@ import fr.iut.cinecool.viewModel.MovieViewModel
import fr.iut.cinecool.R
import fr.iut.cinecool.adapter.MovieAdapter
import fr.iut.cinecool.databinding.FragmentMoviesBinding
import fr.iut.cinecool.model.cineViewModel
import fr.iut.cinecool.viewModel.cineViewModel
class MoviesFragment : Fragment() {
private val sharedViewModel: cineViewModel by activityViewModels()

@ -1,51 +0,0 @@
package fr.iut.cinecool.fragments
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import fr.iut.cinecool.R
import fr.iut.cinecool.model.cineViewModel
class SessionFragment : Fragment() {
private val sharedViewModel: cineViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_session, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
init()
val button = view.findViewById<ImageButton>(R.id.returnButton)
button.setOnClickListener {
findNavController().navigate(R.id.action_SessionFragment_to_fragment_movies)
}
}
private fun init() {
requireView().findViewById<TextView>(R.id.title).text= sharedViewModel.cine.value?.title
val desc = requireView().findViewById<TextView>(R.id.description)
desc.text=sharedViewModel.cine.value?.overview
desc.isScrollContainer = true
desc.movementMethod = ScrollingMovementMethod()
val img=requireView().findViewById<ImageView>(R.id.afficheFilm)
val imageUrl = "https://image.tmdb.org/t/p/w500${sharedViewModel.cine.value?.poster_path}"
Glide.with(this.requireContext())
.load(imageUrl)
.placeholder(R.drawable.no_pictures)
.into(img)
}
}

@ -1,3 +1,23 @@
package fr.iut.cinecool.model
data class Cinema (val id:Int, val latitude:Int, val longitude:Int, val city:String, val name:String, /*var movies:ArrayList<Movie>*/)
data class CinemaResult(
val lat: Double,
val lon: Double,
val display_name: String
)
data class RouteResult(
val routes: List<Route>
)
data class Route(
val segments: List<Segment>
)
data class Segment(
val steps: List<Step>
)
data class Step(
val instruction: String
)

@ -1,5 +1,47 @@
package fr.iut.cinecool.model
package fr.iut.cinecool.API.THMDB
import android.graphics.drawable.Drawable
data class Movie(val id:Int, val name:String, var mark:Int, val realisator:String, var duration: Double, val icon:Int)
import android.os.Parcel
import android.os.Parcelable
data class MovieResponse(
val page: Int,
val results: List<Movie>,
val total_pages: Int,
val total_results: Int
)
data class Movie(
val id: Int,
val title: String,
val poster_path: String?,
val overview: String
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString()!!,
parcel.readString(),
parcel.readString()!!
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(title)
parcel.writeString(poster_path)
parcel.writeString(overview)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Movie> {
override fun createFromParcel(parcel: Parcel): Movie {
return Movie(parcel)
}
override fun newArray(size: Int): Array<Movie?> {
return arrayOfNulls(size)
}
}
}

@ -1,5 +0,0 @@
package fr.iut.cinecool.model
import java.util.Date
data class Session(val id:Int, val date: Date, val beginHour:Int, val endingHour:Int, val room:String)

@ -1,16 +0,0 @@
package fr.iut.cinecool.model
import android.graphics.drawable.Drawable
import fr.iut.cinecool.R
import java.util.Date
class Stub( var sessions:ArrayList<Session> = ArrayList(),var movies:ArrayList<Movie> = ArrayList(),var cinemas:ArrayList<Cinema> = ArrayList()) {
fun loading(){
val date = Date(2023,3,12)
sessions.addAll(listOf(Session(0,date,14,16,"2A"),Session(1,date,4,6,"5B")))
movies.add(Movie(1,"trop bg",2,"Pas moi",2.0, R.drawable.no_pictures))
movies.add(Movie(0,"Imitation Game",4,"Moi",3.0,R.drawable.imitation_game))
cinemas.add(Cinema(0,12367,67894,"clf","CineJaude"))
cinemas.add(Cinema(1,87634,43567,"Aubière","CGR Le Paris"))
}
}

@ -1,4 +1,4 @@
package fr.iut.cinecool.model
package fr.iut.cinecool.viewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData

@ -5,24 +5,24 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import androidx.lifecycle.MutableLiveData
import fr.iut.cinecool.API.THMDB.Movie
import fr.iut.cinecool.API.THMDB.Repository
import fr.iut.cinecool.API.THMDB.MethodApiTHMDB
class MovieViewModel : ViewModel() {
private val repository = Repository()
private val methodApiTHMDB = MethodApiTHMDB()
val popularMovies = MutableLiveData<List<Movie>>()
val searchResults = MutableLiveData<List<Movie>>()
fun getPopularMovies(apiKey: String, page: Int) {
viewModelScope.launch {
val movies = repository.getPopularMovies(apiKey, page)
val movies = methodApiTHMDB.getPopularMovies(apiKey, page)
popularMovies.postValue(movies.results)
}
}
fun searchMovies(apiKey: String, query: String, page: Int) {
viewModelScope.launch {
val movies = repository.searchMovies(apiKey, query, page)
val movies = methodApiTHMDB.searchMovies(apiKey, query, page)
searchResults.postValue(movies.results)
}
}

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CinemaActivity">
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment"

@ -1,11 +0,0 @@
<?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=".fragments.CinemaFragment">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclerCinemas"/>
</FrameLayout>

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<TextView
android:id="@+id/cinema_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Cinema Name" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/movie_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="8dp"
android:clipToPadding="false"
app:layout_constraintTop_toBottomOf="@id/cinema_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:listitem="@layout/movie_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/cinema_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="8dp"
android:clipToPadding="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:listitem="@layout/item_cinema" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.SessionFragment">
tools:context=".fragments.MovieDetailFragment">
<ImageButton
android:id="@+id/returnButton"

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<ImageView
android:id="@+id/Background"
android:layout_width="3000px"
android:layout_height="3000px"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/background" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="300sp"
android:layout_marginBottom="100dp"
android:background="@drawable/login_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Logo"
app:layout_constraintVertical_bias="1.0">
<EditText
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="17"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.49"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.235" />
<ImageView
android:id="@+id/loginButton"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/name"
app:srcCompat="@drawable/connection_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/Logo"
android:layout_width="189dp"
android:layout_height="199dp"
android:layout_marginTop="60dp"
android:background="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/cinema" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<fragment
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"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
tools:context=".MainActivity"/>

@ -20,10 +20,12 @@
android:id="@+id/toolbar"
android:layout_width="211dp"
android:layout_height="27dp"
android:layout_marginTop="16dp"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toStartOf="@+id/settings"
app:layout_constraintHorizontal_bias="0.391"
app:layout_constraintStart_toEndOf="@+id/imageView"
tools:layout_editor_absoluteY="29dp"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints">
<androidx.appcompat.widget.SearchView
@ -31,7 +33,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:iconifiedByDefault="false"
app:queryHint="Rechercher" />
app:queryHint="@string/research" />
</androidx.appcompat.widget.Toolbar>
@ -47,26 +49,27 @@
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
/>
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="All movies"
android:id="@+id/welcomeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:text="@string/welcome"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.534"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintVertical_bias="0.024" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerMovie"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
app:layout_constraintVertical_bias="1.0" />
app:layout_constraintTop_toBottomOf="@+id/welcomeTextView" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,17 +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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/cinemaNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cinema Name"
android:textSize="18sp"
android:textColor="@android:color/black" />
</LinearLayout>

@ -1,25 +0,0 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/movie_title"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>

@ -3,13 +3,18 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/fragment_movies">
app:startDestination="@id/fragment_login">
<fragment
android:id="@+id/CinemaFragment"
android:name="fr.iut.cinecool.fragments.CinemaFragment"
android:label="Cinema Fragment"
tools:layout="@layout/fragment_cinema"/>
android:id="@+id/fragment_login"
android:name="fr.iut.cinecool.fragments.LoginFragment"
android:label="login_fragment"
tools:layout="@layout/fragment_login">
<action
android:id="@+id/login_to_movies"
app:destination="@id/fragment_movies" />
</fragment>
<fragment
android:id="@+id/fragment_movies"
@ -21,16 +26,13 @@
android:id="@+id/movies_to_sessions"
app:destination="@id/SessionFragment">
</action>
<action
android:id="@+id/movies_to_cinema"
app:destination="@id/CinemaFragment" />
</fragment>
<fragment
android:id="@+id/SessionFragment"
android:name="fr.iut.cinecool.fragments.SessionFragment"
android:name="fr.iut.cinecool.fragments.MovieDetailFragment"
android:label="SessionFragment"
tools:layout="@layout/fragment_session">
tools:layout="@layout/fragment_detail">
<action
android:id="@+id/action_SessionFragment_to_fragment_movies"
app:destination="@id/fragment_movies" />

@ -0,0 +1,16 @@
<resources>
<string name="app_name">CineCool</string>
<string name="title_activity_main">MainActivity</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Suivant</string>
<string name="previous">Précédent</string>
<string name="hello_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="error_loading_movie">erreur de chargement des films</string>
<string name="tmdb_api_key">a97243d7813d31446f6c43284e6854d5</string>
<string name="welcome">Bienvenue dans CineCool</string>
<string name="research">Recherche</string>
</resources>

@ -11,5 +11,6 @@
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="error_loading_movie">erreur de chargement des films</string>
<string name="tmdb_api_key">a97243d7813d31446f6c43284e6854d5</string>
<string name="movie_title">Movie Title</string>
<string name="welcome">Welcome on CineCool</string>
<string name="research">Research</string>
</resources>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<osmdroid>
<preference name="osmdroid.basePath" value="osmdroid" />
<preference name="osmdroid.cachePath" value="tiles" />
</osmdroid>
Loading…
Cancel
Save