Compare commits
5 Commits
a3ff36ba67
...
4d86cd0630
Author | SHA1 | Date | |
---|---|---|---|
4d86cd0630 | |||
b55ee94d8a | |||
7bee8910ec | |||
d6f352be29 | |||
52816c155b |
@ -17,8 +17,8 @@ android {
|
|||||||
applicationId = "ru.risdeveau.geotracker"
|
applicationId = "ru.risdeveau.geotracker"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 2
|
||||||
versionName = "1.0"
|
versionName = "1.1"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,11 @@ suspend fun health(baseurl: String): Boolean {
|
|||||||
suspend fun sendGeo(baseurl: String = SettingsPreferences.url, data: GeoData): Boolean {
|
suspend fun sendGeo(baseurl: String = SettingsPreferences.url, data: GeoData): Boolean {
|
||||||
try {
|
try {
|
||||||
val json = JSONObject()
|
val json = JSONObject()
|
||||||
json.put("ln", data.ln)
|
json.put("lon", data.ln)
|
||||||
json.put("lt", data.lt)
|
json.put("lat", data.lt)
|
||||||
json.put("nick", data.nick)
|
json.put("user_name", data.nick)
|
||||||
|
|
||||||
client.post("$baseurl/map") {
|
client.post("$baseurl/api/app") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
setBody(json.toString(2))
|
setBody(json.toString(2))
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package ru.risdeveau.geotracker
|
|||||||
import splitties.preferences.Preferences
|
import splitties.preferences.Preferences
|
||||||
|
|
||||||
object SettingsPreferences : Preferences("settings") {
|
object SettingsPreferences : Preferences("settings") {
|
||||||
var username by stringPref("username", "anonimous")
|
var username by stringPref("username", "")
|
||||||
var url by stringPref("url", "https://example.com")
|
var url by stringPref("url", "https://geo.tmp.codrs.ru")
|
||||||
|
val interval by IntPref("interval", 15)
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ import android.Manifest.permission.POST_NOTIFICATIONS
|
|||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@ -41,12 +42,14 @@ class LocationForegroundService : Service() {
|
|||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
Log.d("Service", "onStartCommand")
|
Log.d("Service", "onStartCommand")
|
||||||
|
|
||||||
if (!(hasPermission(ACCESS_FINE_LOCATION)
|
if (
|
||||||
|
!(hasPermission(ACCESS_FINE_LOCATION)
|
||||||
&& (
|
&& (
|
||||||
(Build.VERSION.SDK_INT < 33)
|
(Build.VERSION.SDK_INT < 33)
|
||||||
|| hasPermission(POST_NOTIFICATIONS)
|
|| hasPermission(POST_NOTIFICATIONS)
|
||||||
)
|
))
|
||||||
)) {
|
|| intent?.action == ACTION_STOP_SERVICE
|
||||||
|
) {
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
@ -55,11 +58,12 @@ class LocationForegroundService : Service() {
|
|||||||
val notification = createNotification()
|
val notification = createNotification()
|
||||||
startForeground(1, notification)
|
startForeground(1, notification)
|
||||||
|
|
||||||
locationTracker.startTracking(5000)
|
locationTracker.startTracking(SettingsPreferences.interval * 1000L)
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
Log.d("Service", "Destroyed")
|
||||||
locationTracker.stopTracking()
|
locationTracker.stopTracking()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
@ -69,8 +73,8 @@ class LocationForegroundService : Service() {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channel = NotificationChannel(
|
val channel = NotificationChannel(
|
||||||
"location_channel",
|
"location_channel",
|
||||||
"Location Tracking",
|
"Отправка Местоположения",
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
)
|
)
|
||||||
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
manager.createNotificationChannel(channel)
|
manager.createNotificationChannel(channel)
|
||||||
@ -78,12 +82,36 @@ class LocationForegroundService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotification(): Notification {
|
private fun createNotification(): Notification {
|
||||||
|
val stopIntent = Intent(this, LocationForegroundService::class.java).apply {
|
||||||
|
action = ACTION_STOP_SERVICE
|
||||||
|
}
|
||||||
|
|
||||||
|
val stopPendingIntent = PendingIntent.getService(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
stopIntent,
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
|
else
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
|
||||||
return NotificationCompat.Builder(this, "location_channel")
|
return NotificationCompat.Builder(this, "location_channel")
|
||||||
.setContentTitle("Отслеживание местоположения")
|
.setContentTitle("Отслеживание местоположения")
|
||||||
.setContentText("Обновление каждые 5 секунд")
|
.setContentText("Обновление каждые ${SettingsPreferences.interval} секунд")
|
||||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
.setSmallIcon(R.drawable.share_location)
|
||||||
|
.addAction(
|
||||||
|
R.drawable.cancel,
|
||||||
|
"Остановить",
|
||||||
|
stopPendingIntent
|
||||||
|
)
|
||||||
|
.setOngoing(true)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? = null
|
override fun onBind(intent: Intent?): IBinder? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ACTION_STOP_SERVICE = "ru.risdeveau.geotracker.STOP_SERVICE"
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Done
|
import androidx.compose.material.icons.outlined.Done
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@ -33,6 +34,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@ -40,6 +42,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -89,6 +92,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
launch {
|
launch {
|
||||||
screen = if (
|
screen = if (
|
||||||
health(SettingsPreferences.url)
|
health(SettingsPreferences.url)
|
||||||
|
&& SettingsPreferences.username.isNotBlank()
|
||||||
&& hasPermission(ACCESS_FINE_LOCATION)
|
&& hasPermission(ACCESS_FINE_LOCATION)
|
||||||
&& (
|
&& (
|
||||||
(Build.VERSION.SDK_INT < 33)
|
(Build.VERSION.SDK_INT < 33)
|
||||||
@ -121,6 +125,7 @@ sealed class Screen {
|
|||||||
fun Settings(modifier: Modifier = Modifier, onConfirm: () -> Unit) {
|
fun Settings(modifier: Modifier = Modifier, onConfirm: () -> Unit) {
|
||||||
var username by remember { mutableStateOf(SettingsPreferences.username) }
|
var username by remember { mutableStateOf(SettingsPreferences.username) }
|
||||||
var url by remember { mutableStateOf(SettingsPreferences.url) }
|
var url by remember { mutableStateOf(SettingsPreferences.url) }
|
||||||
|
var interval by remember { mutableIntStateOf(SettingsPreferences.interval) }
|
||||||
var urlIsValid by remember { mutableStateOf(false) }
|
var urlIsValid by remember { mutableStateOf(false) }
|
||||||
var loading by remember { mutableStateOf(false) }
|
var loading by remember { mutableStateOf(false) }
|
||||||
var fineLoc by remember { mutableStateOf(hasPermission(ACCESS_FINE_LOCATION)) }
|
var fineLoc by remember { mutableStateOf(hasPermission(ACCESS_FINE_LOCATION)) }
|
||||||
@ -162,6 +167,17 @@ fun Settings(modifier: Modifier = Modifier, onConfirm: () -> Unit) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = interval.toString(),
|
||||||
|
onValueChange = {
|
||||||
|
val newVal = it.toIntOrNull()
|
||||||
|
if (newVal != null)
|
||||||
|
interval = newVal.coerceIn(1..300)
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
label = { Text("Интервал отправки") }
|
||||||
|
)
|
||||||
|
|
||||||
GetPermission(ACCESS_FINE_LOCATION) { fineLoc = true; }
|
GetPermission(ACCESS_FINE_LOCATION) { fineLoc = true; }
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 33)
|
if (Build.VERSION.SDK_INT >= 33)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user