Merge pull request 'arthur' (#4) from arthur into master

Reviewed-on: baptiste.bonneau/Geocaching#4
pull/6/head
Arthur VALIN 2 years ago
commit a9d12b6538

@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}
android {
@ -40,4 +41,7 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.fragment:fragment-ktx:1.5.5"
implementation 'org.osmdroid:osmdroid-android:6.1.14'
}

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools" >
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_A"/>
<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" />
<application
android:allowBackup="true"
@ -11,15 +19,14 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Geocaching"
tools:targetApi="31">
<activity android:name=".MainWindow" android:exported="true">
tools:targetApi="31" >
<activity
android:name=".MainWindow"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

@ -0,0 +1,59 @@
package uca.baptistearthur.geocaching
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
// 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)
}
}
}
}

@ -2,12 +2,41 @@ package uca.baptistearthur.geocaching
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView
import org.osmdroid.config.Configuration
class MainWindow: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_window)
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(List())
true
}
else -> false
}
}
}
private fun loadFragment(fragment: Fragment){
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
transaction.commit()
}
}

@ -0,0 +1,106 @@
package uca.baptistearthur.geocaching
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 androidx.fragment.app.Fragment
import org.osmdroid.config.Configuration
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.ScaleBarOverlay
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.hardware.SensorManager
import android.location.Location
import android.location.LocationListener
import androidx.activity.result.contract.ActivityResultContracts
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
class Map : Fragment() {
private lateinit var map : MapView
val defaultPoint = GeoPoint(48.8583, 2.2944)
var isMapCentered = false;
val locationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
val geoPoint = GeoPoint(location.latitude, location.longitude)
if(!isMapCentered){
map.controller.setCenter(geoPoint)
isMapCentered=true;
}
map.invalidate()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Configuration.getInstance().userAgentValue = "Geocaching"
}
val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission())
{ map.controller.setCenter(defaultPoint); }
private fun configureMap(view: View){
map = view.findViewById(R.id.mapView)
map.controller.setZoom(20.0);
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(ACCESS_FINE_LOCATION)
}
map.controller.setCenter(defaultPoint)
val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), map);
compassOverlay.enableCompass();
map.getOverlays().add(compassOverlay);
val scaleBarOverlay = ScaleBarOverlay(map)
scaleBarOverlay.setAlignRight(true)
map.overlays.add(scaleBarOverlay)
val myLocation = MyLocationNewOverlay(GpsMyLocationProvider(context), map)
myLocation.enableFollowLocation()
myLocation.enableMyLocation()
map.overlays.add(myLocation)
val recenter = RecenterOverlay(GpsMyLocationProvider(context), map)
recenter.enableMyLocation()
map.overlays.add(recenter);
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_map, container, false)
configureMap(view)
return view
}
override fun onResume() {
super.onResume()
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListener)
}
map.onResume() //needed for compass, my location overlays, v6.0.0 and up
}
override fun onPause() {
super.onPause()
if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(locationListener)
isMapCentered=false;
}
map.onPause() //needed for compass, my location overlays, v6.0.0 and up
}
}

@ -0,0 +1,59 @@
package uca.baptistearthur.geocaching
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
// 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)
}
}
}
}

@ -0,0 +1,93 @@
package uca.baptistearthur.geocaching
import android.graphics.*
import android.graphics.drawable.shapes.Shape
import android.location.Location
import android.view.GestureDetector
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatDrawableManager
import androidx.core.content.ContextCompat
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.Overlay
import org.osmdroid.views.overlay.mylocation.IMyLocationConsumer
import org.osmdroid.views.overlay.mylocation.IMyLocationProvider
class RecenterOverlay(val myLocationProvider: IMyLocationProvider, val mapView: MapView) : Overlay(), GestureDetector.OnGestureListener, IMyLocationConsumer {
private val gestureDetector: GestureDetector = GestureDetector(mapView.context, this)
private var circleRectF=RectF();
override fun draw(canvas: Canvas, mapView: MapView, shadow: Boolean) {
val circleSize = 300f
val circlePadding = 20f
val circleX = canvas.width - circleSize - circlePadding
val circleY = canvas.height - circleSize - circlePadding
circleRectF=RectF(circleX, circleY, circleX + circleSize, circleY + circleSize)
val paint = Paint().apply {
color = Color.WHITE
style = Paint.Style.FILL
}
canvas.drawCircle(
circleX + circleSize / 2,
circleY + circleSize / 2,
circleSize / 2,
paint
)
val iconSize = 180
val icon = ContextCompat.getDrawable(mapView.context, R.drawable.center)
val iconX = (circleX + circleSize / 2 - iconSize / 2).toInt()
val iconY = (circleY + circleSize / 2 - iconSize / 2).toInt()
icon?.setBounds(iconX, iconY, iconX + iconSize, iconY + iconSize)
icon?.draw(canvas)
}
fun enableMyLocation() {
myLocationProvider.startLocationProvider(this);
}
fun disableMyLocation(){
myLocationProvider.stopLocationProvider();
}
override fun onSingleTapConfirmed(e: MotionEvent?, mapView: MapView?) =
myLocationProvider.lastKnownLocation?.let {
if (e != null && circleRectF.contains(e.x, e.y)) {
mapView?.controller?.setCenter(GeoPoint(it.latitude, it.longitude))
mapView?.controller?.setZoom(20.0);
}
true
} ?: false
override fun onResume() {
super.onResume()
enableMyLocation()
}
override fun onPause(){
disableMyLocation()
super.onPause()
}
override fun onDetach(mapView: MapView?) {
disableMyLocation()
super.onDetach(mapView)
}
override fun onDown(p0: MotionEvent) = true
override fun onShowPress(p0: MotionEvent) = Unit
override fun onSingleTapUp(p0: MotionEvent) = true
override fun onScroll(p0: MotionEvent, p1: MotionEvent, p2: Float, p3: Float) = true;
override fun onLongPress(p0: MotionEvent) = Unit
override fun onFling(p0: MotionEvent, p1: MotionEvent, p2: Float, p3: Float) = true
override fun onLocationChanged(location: Location?, source: IMyLocationProvider?) = Unit
}

@ -0,0 +1,5 @@
<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="M5,15L3,15v4c0,1.1 0.9,2 2,2h4v-2L5,19v-4zM5,5h4L9,3L5,3c-1.1,0 -2,0.9 -2,2v4h2L5,5zM19,3h-4v2h4v4h2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19h-4v2h4c1.1,0 2,-0.9 2,-2v-4h-2v4zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" 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="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM4,4.5c-0.83,0 -1.5,0.67 -1.5,1.5S3.17,7.5 4,7.5 5.5,6.83 5.5,6 4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.68 -1.5,1.5s0.68,1.5 1.5,1.5 1.5,-0.68 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2zM7,5v2h14L21,5L7,5z"/>
</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="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48V20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48V3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM15,19l-6,-2.11V5l6,2.11V19z"/>
</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>

@ -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=".List">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="List" />
</FrameLayout>

@ -0,0 +1,15 @@
<?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=".Map">
<org.osmdroid.views.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true" />
</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=".Profile">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="PROFILE" />
</FrameLayout>

@ -1,66 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<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="match_parent"
android:orientation="vertical">
<!-- Trouver un moyen de virer le menu par défaut ou le garder et virer le frameLayout en dessous-->
<FrameLayout
<TextView
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/green">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/app_name"
android:textColor="@color/white"
android:layout_marginStart="25dp"
android:gravity="center"
android:textSize="20sp"
android:layout_marginLeft="25dp" />
</FrameLayout>
<!-- Ici map, j'ai essayé de télécharger la map de google dans "Design" mais ca a cassé le projet donc à éviter pour l'instant je pense-->
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/main_turquoise_700"
android:gravity="center_vertical"
android:padding="20dp"
android:text="@string/app_name"
android:textColor="@color/main_turquoise_50"
android:textSize="20sp"
android:textStyle="bold" />
<!-- Arriver à mettre le menu en bas + Ajouter des icones-->
<!-- Faire un composant pour éviter la répétition ?-->
<LinearLayout
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="55dp"
android:gravity="center"
>
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/profil"
android:textSize="11sp"
android:layout_marginRight="20dp"
style="?android:attr/buttonBarButtonStyle"/>
android:layout_height="0dp"
android:layout_weight="8"/>
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/carte"
android:textSize="11sp"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
style="?android:attr/buttonBarButtonStyle" />
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/liste"
android:textSize="11sp"
android:layout_marginLeft="20dp"
style="?android:attr/buttonBarButtonStyle"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/main_turquoise_700"
app:menu="@menu/bottom_tabs" />
</LinearLayout>
</LinearLayout>

@ -0,0 +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/carte"
android:icon="@drawable/map"/>
<item
android:id="@+id/list"
android:enabled="true"
android:title="@string/liste"
android:icon="@drawable/list" />
</menu>

@ -1,9 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Geocaching" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Geocaching" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorPrimary">@color/purple_700</item>
<item name="colorPrimaryVariant">@color/purple_200</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>

@ -9,4 +9,9 @@
<color name="white">#FFFFFFFF</color>
<color name="green">#FF3D7D3C</color>
<color name="green_variant">#FF659964</color>
<color name="main_turquoise_700">#2f3e46</color>
<color name="main_turquoise_500">#354f52</color>
<color name="main_turquoise_200">#52796f</color>
<color name="main_turquoise_50">#cad2c5</color>
</resources>

@ -3,4 +3,6 @@
<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,9 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Geocaching" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Geocaching" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/green</item>
<item name="colorPrimaryVariant">@color/green_variant</item>
<item name="colorPrimary">@color/main_turquoise_50</item>
<item name="colorPrimaryVariant">@color/main_turquoise_500</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>

@ -3,4 +3,5 @@ plugins {
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
}

@ -3,6 +3,7 @@ pluginManagement {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {

Loading…
Cancel
Save