Skip to content

Commit d81ad14

Browse files
author
F4DIW
committed
Correction des permissions GPS et amélioration de la précision de localisation
1 parent 00a9094 commit d81ad14

15 files changed

Lines changed: 300 additions & 63 deletions

File tree

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ android {
1919
versionName = "1.0"
2020

2121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
22+
resConfigs("en", "fr", "ru")
2223
}
2324

2425
buildTypes {
@@ -49,6 +50,7 @@ dependencies {
4950
implementation(libs.androidx.compose.ui.tooling.preview)
5051
implementation(libs.androidx.core.ktx)
5152
implementation(libs.androidx.core.splashscreen)
53+
implementation(libs.playServicesLocation)
5254
implementation(libs.androidx.appcompat)
5355
implementation(libs.androidx.fragment.ktx)
5456
implementation(libs.material)

app/src/main/AndroidManifest.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
77
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
88
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
9+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
10+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
911

1012
<application
1113
android:allowBackup="true"
@@ -15,7 +17,8 @@
1517
android:label="@string/app_name"
1618
android:roundIcon="@mipmap/ic_launcher_round"
1719
android:supportsRtl="true"
18-
android:theme="@style/Theme.F4DIWRotatorApp">
20+
android:theme="@style/Theme.F4DIWRotatorApp"
21+
android:localeConfig="@xml/locales_config">
1922
<activity
2023
android:name=".SplashActivity"
2124
android:exported="true"
@@ -30,6 +33,15 @@
3033
android:name=".MainActivity"
3134
android:exported="false"
3235
android:theme="@style/Theme.F4DIWRotatorApp" />
36+
37+
<service
38+
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
39+
android:enabled="false"
40+
android:exported="false">
41+
<meta-data
42+
android:name="auto_store_locales"
43+
android:value="true" />
44+
</service>
3345
</application>
3446

3547
</manifest>

app/src/main/java/com/example/f4diwrotatorapp/MainActivity.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.example.f4diwrotatorapp
22

33
import android.Manifest
4+
import android.content.Context
45
import android.content.pm.PackageManager
56
import android.os.Build
67
import android.os.Bundle
78
import androidx.appcompat.app.AppCompatActivity
9+
import androidx.appcompat.app.AppCompatDelegate
810
import androidx.core.app.ActivityCompat
11+
import androidx.core.os.LocaleListCompat
912
import androidx.fragment.app.Fragment
1013
import androidx.lifecycle.lifecycleScope
1114
import com.example.f4diwrotatorapp.databinding.ActivityMainBinding
@@ -59,15 +62,20 @@ class MainActivity : AppCompatActivity() {
5962

6063
private fun checkPermissions() {
6164
val permissions = mutableListOf<String>()
65+
66+
// Bluetooth permissions
6267
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
6368
permissions.add(Manifest.permission.BLUETOOTH_CONNECT)
6469
permissions.add(Manifest.permission.BLUETOOTH_SCAN)
6570
} else {
6671
permissions.add(Manifest.permission.BLUETOOTH)
6772
permissions.add(Manifest.permission.BLUETOOTH_ADMIN)
68-
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
6973
}
7074

75+
// Location permissions (needed for Bluetooth and GPS position)
76+
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
77+
permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION)
78+
7179
val toRequest = permissions.filter {
7280
ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
7381
}.toTypedArray()

app/src/main/java/com/example/f4diwrotatorapp/SplashActivity.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.example.f4diwrotatorapp
22

33
import android.annotation.SuppressLint
4+
import android.content.Context
45
import android.content.Intent
56
import android.os.Bundle
67
import android.os.Handler
78
import android.os.Looper
89
import androidx.appcompat.app.AppCompatActivity
10+
import androidx.appcompat.app.AppCompatDelegate
11+
import androidx.core.os.LocaleListCompat
912

1013
@SuppressLint("CustomSplashScreen")
1114
class SplashActivity : AppCompatActivity() {

app/src/main/java/com/example/f4diwrotatorapp/ui/settings/SettingsFragment.kt

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package com.example.f4diwrotatorapp.ui.settings
22

33
import android.content.Context
4+
import android.content.pm.PackageManager
45
import android.os.Bundle
56
import android.view.LayoutInflater
67
import android.view.View
78
import android.view.ViewGroup
9+
import android.widget.Toast
810
import androidx.appcompat.app.AppCompatDelegate
11+
import androidx.core.app.ActivityCompat
912
import androidx.core.os.LocaleListCompat
1013
import androidx.fragment.app.Fragment
1114
import com.example.f4diwrotatorapp.R
1215
import com.example.f4diwrotatorapp.databinding.FragmentSettingsBinding
16+
import com.example.f4diwrotatorapp.utils.GeoUtils
17+
import com.google.android.gms.location.LocationServices
1318
import com.google.android.material.dialog.MaterialAlertDialogBuilder
19+
import java.text.SimpleDateFormat
20+
import java.util.Date
21+
import java.util.Locale
1422

1523
class SettingsFragment : Fragment() {
1624

@@ -28,6 +36,8 @@ class SettingsFragment : Fragment() {
2836
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2937
super.onViewCreated(view, savedInstanceState)
3038

39+
loadSavedPosition()
40+
3141
binding.cardBluetooth.setOnClickListener {
3242
parentFragmentManager.beginTransaction()
3343
.replace(R.id.fragmentContainer, BluetoothSettingsFragment())
@@ -45,6 +55,72 @@ class SettingsFragment : Fragment() {
4555
binding.cardLanguage.setOnClickListener {
4656
showLanguageDialog()
4757
}
58+
59+
binding.btnGpsUpdate.setOnClickListener {
60+
updatePositionGps()
61+
}
62+
}
63+
64+
private fun loadSavedPosition() {
65+
val prefs = requireContext().getSharedPreferences("settings", Context.MODE_PRIVATE)
66+
val lat = prefs.getFloat("station_lat", 0f).toDouble()
67+
val lon = prefs.getFloat("station_lon", 0f).toDouble()
68+
val lastUpdate = prefs.getString("station_last_update", "--/-- --:--")
69+
70+
updateUiWithPosition(lat, lon, lastUpdate)
71+
}
72+
73+
private fun updatePositionGps() {
74+
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
75+
ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
76+
77+
// On demande la permission si elle est manquante
78+
ActivityCompat.requestPermissions(requireActivity(),
79+
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION),
80+
2)
81+
return
82+
}
83+
84+
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
85+
86+
// On essaie d'abord de récupérer la dernière position connue (rapide)
87+
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
88+
if (location != null) {
89+
saveAndDisplayLocation(location.latitude, location.longitude)
90+
} else {
91+
// Si la dernière position est nulle, on demande une mise à jour fraîche (plus lent mais précis)
92+
Toast.makeText(requireContext(), "Recherche du signal GPS...", Toast.LENGTH_SHORT).show()
93+
val priority = com.google.android.gms.location.Priority.PRIORITY_HIGH_ACCURACY
94+
fusedLocationClient.getCurrentLocation(priority, null).addOnSuccessListener { freshLocation ->
95+
if (freshLocation != null) {
96+
saveAndDisplayLocation(freshLocation.latitude, freshLocation.longitude)
97+
} else {
98+
Toast.makeText(requireContext(), "GPS indisponible. Vérifiez qu'il est activé.", Toast.LENGTH_SHORT).show()
99+
}
100+
}
101+
}
102+
}
103+
}
104+
105+
private fun saveAndDisplayLocation(lat: Double, lon: Double) {
106+
val sdf = SimpleDateFormat("dd/MM HH:mm", Locale.getDefault())
107+
val lastUpdate = sdf.format(Date())
108+
109+
val prefs = requireContext().getSharedPreferences("settings", Context.MODE_PRIVATE)
110+
prefs.edit()
111+
.putFloat("station_lat", lat.toFloat())
112+
.putFloat("station_lon", lon.toFloat())
113+
.putString("station_last_update", lastUpdate)
114+
.apply()
115+
116+
updateUiWithPosition(lat, lon, lastUpdate)
117+
Toast.makeText(requireContext(), "Position mise à jour", Toast.LENGTH_SHORT).show()
118+
}
119+
120+
private fun updateUiWithPosition(lat: Double, lon: Double, lastUpdate: String?) {
121+
binding.tvLatLon.text = getString(R.string.label_lat_lon, lat, lon)
122+
binding.tvQth.text = getString(R.string.label_qth, GeoUtils.getQTHLocator(lat, lon))
123+
binding.tvLastUpdate.text = getString(R.string.label_last_update, lastUpdate ?: "--/-- --:--")
48124
}
49125

50126
private fun showLanguageDialog() {
@@ -60,13 +136,15 @@ class SettingsFragment : Fragment() {
60136
}
61137

62138
private fun setLocale(languageCode: String) {
63-
// Méthode moderne recommandée par Android pour changer la langue sans redémarrage manuel complexe
64139
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageCode)
65140
AppCompatDelegate.setApplicationLocales(appLocale)
66141

67-
// Sauvegarde dans les préférences pour persistance (optionnel car géré par AppCompatDelegate sur API récentes)
142+
// On sauvegarde manuellement pour la persistance
68143
val prefs = requireContext().getSharedPreferences("settings", Context.MODE_PRIVATE)
69144
prefs.edit().putString("language_code", languageCode).apply()
145+
146+
// Force la recréation pour appliquer les changements immédiatement sur tous les écrans
147+
requireActivity().recreate()
70148
}
71149

72150
override fun onDestroyView() {

app/src/main/java/com/example/f4diwrotatorapp/utils/GeoUtils.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,25 @@ object GeoUtils {
2626
sin(dLon / 2).pow(2)
2727
return 2 * EARTH_RADIUS_KM * asin(sqrt(a))
2828
}
29+
30+
// ── Calcul du QTH Locator (Maidenhead) ────────────────────────
31+
fun getQTHLocator(lat: Double, lon: Double): String {
32+
var lonRel = lon + 180.0
33+
var latRel = lat + 90.0
34+
35+
val field1 = ('A'.code + (lonRel / 20.0).toInt()).toChar()
36+
val field2 = ('A'.code + (latRel / 10.0).toInt()).toChar()
37+
38+
lonRel %= 20.0
39+
latRel %= 10.0
40+
val square1 = ('0'.code + (lonRel / 2.0).toInt()).toChar()
41+
val square2 = ('0'.code + (latRel / 1.0).toInt()).toChar()
42+
43+
lonRel %= 2.0
44+
latRel %= 1.0
45+
val subsquare1 = ('a'.code + (lonRel * 12.0).toInt()).toChar().uppercaseChar()
46+
val subsquare2 = ('a'.code + (latRel * 24.0).toInt()).toChar().uppercaseChar()
47+
48+
return "$field1$field2$square1$square2$subsquare1$subsquare2"
49+
}
2950
}

app/src/main/res/layout/activity_main.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919
android:background="@color/bg_card"
2020
app:itemIconTint="@color/white"
2121
app:itemTextColor="@color/white"
22-
app:menu="@menu/bottom_nav_menu" />
22+
app:menu="@menu/bottom_nav_menu"
23+
app:labelVisibilityMode="labeled" />
2324
</LinearLayout>

app/src/main/res/layout/fragment_control.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@
122122
android:layout_width="0dp"
123123
android:layout_height="wrap_content"
124124
android:layout_weight="1"
125-
android:hint="AZ (0-360°)"
125+
android:hint="@string/label_az"
126126
android:layout_marginEnd="10dp"
127127
app:hintTextColor="@color/white"
128128
app:boxStrokeColor="@color/white"
@@ -147,7 +147,7 @@
147147
android:layout_width="0dp"
148148
android:layout_height="wrap_content"
149149
android:layout_weight="1"
150-
android:hint="EL (0-90°)"
150+
android:hint="@string/label_el"
151151
app:hintTextColor="@color/white"
152152
app:boxStrokeColor="@color/white"
153153
app:boxBackgroundColor="@color/bg_card"

app/src/main/res/layout/fragment_settings.xml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
android:id="@+id/cardLanguage"
127127
android:layout_width="match_parent"
128128
android:layout_height="wrap_content"
129+
android:layout_marginBottom="16dp"
129130
android:clickable="true"
130131
android:focusable="true"
131132
app:cardCornerRadius="16dp"
@@ -170,5 +171,85 @@
170171
</LinearLayout>
171172
</com.google.android.material.card.MaterialCardView>
172173

174+
<!-- Option Position -->
175+
<com.google.android.material.card.MaterialCardView
176+
android:id="@+id/cardPosition"
177+
android:layout_width="match_parent"
178+
android:layout_height="wrap_content"
179+
app:cardCornerRadius="16dp"
180+
app:cardBackgroundColor="@color/bg_card"
181+
app:strokeWidth="0dp">
182+
183+
<LinearLayout
184+
android:layout_width="match_parent"
185+
android:layout_height="wrap_content"
186+
android:orientation="vertical"
187+
android:padding="20dp">
188+
189+
<LinearLayout
190+
android:layout_width="match_parent"
191+
android:layout_height="wrap_content"
192+
android:orientation="horizontal"
193+
android:gravity="center_vertical"
194+
android:layout_marginBottom="16dp">
195+
196+
<ImageView
197+
android:layout_width="24dp"
198+
android:layout_height="24dp"
199+
android:src="@android:drawable/ic_menu_mylocation"
200+
app:tint="@color/white" />
201+
202+
<TextView
203+
android:layout_width="0dp"
204+
android:layout_height="wrap_content"
205+
android:layout_weight="1"
206+
android:text="@string/title_position"
207+
android:textColor="@color/white"
208+
android:textSize="18sp"
209+
android:textStyle="bold"
210+
android:layout_marginStart="16dp" />
211+
</LinearLayout>
212+
213+
<TextView
214+
android:id="@+id/tvLatLon"
215+
android:layout_width="match_parent"
216+
android:layout_height="wrap_content"
217+
android:text="Lat: 0.00000 / Lon: 0.00000"
218+
android:textColor="@color/white"
219+
android:textSize="14sp"
220+
android:layout_marginBottom="4dp" />
221+
222+
<TextView
223+
android:id="@+id/tvQth"
224+
android:layout_width="match_parent"
225+
android:layout_height="wrap_content"
226+
android:text="QTH: ------"
227+
android:textColor="@color/accent_blue"
228+
android:textSize="16sp"
229+
android:textStyle="bold"
230+
android:layout_marginBottom="4dp" />
231+
232+
<TextView
233+
android:id="@+id/tvLastUpdate"
234+
android:layout_width="match_parent"
235+
android:layout_height="wrap_content"
236+
android:text="Updated: --/-- --:--"
237+
android:textColor="@color/text_secondary"
238+
android:textSize="12sp"
239+
android:layout_marginBottom="16dp" />
240+
241+
<com.google.android.material.button.MaterialButton
242+
android:id="@+id/btnGpsUpdate"
243+
android:layout_width="match_parent"
244+
android:layout_height="wrap_content"
245+
android:text="@string/btn_gps_update"
246+
android:backgroundTint="@color/bg_main"
247+
android:textColor="@color/white"
248+
app:strokeColor="@color/accent_blue"
249+
app:strokeWidth="1dp"
250+
app:cornerRadius="12dp" />
251+
</LinearLayout>
252+
</com.google.android.material.card.MaterialCardView>
253+
173254
</LinearLayout>
174255
</ScrollView>

0 commit comments

Comments
 (0)