Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Client/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Client/.idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 8 additions & 9 deletions Client/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 24 additions & 22 deletions Client/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ android {

defaultConfig {
applicationId = "com.example.evroutes"
minSdk = 24
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
Expand All @@ -20,6 +20,12 @@ android {
}
}

packaging {
jniLibs {
useLegacyPackaging = true
}
}

buildTypes {
release {
isMinifyEnabled = false
Expand Down Expand Up @@ -47,27 +53,23 @@ android {
}

dependencies {
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6")
implementation("androidx.activity:activity-compose:1.9.3")
implementation(platform("androidx.compose:compose-bom:2024.10.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
// Навигация
implementation("androidx.navigation:navigation-compose:2.8.3")
// Retrofit для сетевых запросов
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)

implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)

implementation(libs.yandex.maps)
implementation(libs.androidx.navigation.compose)
implementation(libs.retrofit)
implementation(libs.retrofit.gson)
implementation(libs.okhttp)
implementation(libs.androidx.lifecycle.viewmodel.compose)

// ViewModel
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.10.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
9 changes: 6 additions & 3 deletions Client/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:name=".EVRoutesApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -15,6 +17,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DiplomEVRoutes"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand All @@ -23,7 +27,6 @@
android:theme="@style/Theme.DiplomEVRoutes">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.evroutes

import android.app.Application
import com.yandex.mapkit.MapKitFactory

class EVRoutesApplication : Application() {

companion object {
private const val MAPKIT_API_KEY = "b328cf2c-247b-45e8-8013-9ecd243b7671"
}

override fun onCreate() {
super.onCreate()
MapKitFactory.setApiKey(MAPKIT_API_KEY)
MapKitFactory.initialize(this)
}
}
129 changes: 123 additions & 6 deletions Client/app/src/main/java/com/example/evroutes/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,37 +1,151 @@
package com.example.evroutes

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.*
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.evroutes.ui.theme.EVRoutesTheme

import com.example.evroutes.data.network.RetrofitClient

import com.example.evroutes.data.repository.AuthRepository
import com.example.evroutes.ui.auth.AuthViewModel
import com.example.evroutes.ui.auth.LoginScreen
import com.example.evroutes.ui.auth.RegisterScreen
import com.example.evroutes.ui.theme.EVRoutesTheme

import com.example.evroutes.data.repository.MapRepository
import com.example.evroutes.ui.map.MapScreen
import com.example.evroutes.ui.map.MapViewModel

import com.yandex.mapkit.MapKitFactory

// Главная активность приложения
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

private var hasLocationPermissions = false

// Регистрируем лаунчер для запроса разрешений
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val coarseGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false
val fineGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false

hasLocationPermissions = coarseGranted || fineGranted

if (hasLocationPermissions) {
println("✅ Location permissions granted")
} else {
println("❌ Location permissions denied")
}

// Перезапускаем UI
setContent {
EVRoutesTheme {
EVRoutesApp()
EVRoutesApp(hasLocationPermissions)
}
}
}

private fun checkAndRequestLocationPermissions() {
val coarseGranted = ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED

val fineGranted = ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED

hasLocationPermissions = coarseGranted || fineGranted

if (hasLocationPermissions) {
println("✅ Location permissions already granted")
setContent {
EVRoutesTheme {
EVRoutesApp(true)
}
}
} else {
println("⚠️ Requesting location permissions...")
// Запрашиваем разрешения
requestPermissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
)
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapKitFactory.initialize(this)
checkAndRequestLocationPermissions()
}

override fun onStart() {
super.onStart()

try {
MapKitFactory.getInstance().onStart()
} catch (e: Exception) {
print("Текст без переноса строки")
}
}

override fun onStop() {
try {
MapKitFactory.getInstance().onStop()
} catch (e: Exception) {
print("Текст без переноса строки")
}
super.onStop()
}
}

// Настройка навигации приложения
@Composable
fun EVRoutesApp() {
fun EVRoutesApp(hasLocationPermissions: Boolean = false) {
val navController = rememberNavController()

if (!hasLocationPermissions) {
// Показываем сообщение о необходимости разрешений
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(16.dp)
) {
Text("Для работы с картами необходимо")
Text("разрешение на доступ к местоположению")
Spacer(modifier = Modifier.height(8.dp))
Text("Пожалуйста, разрешите доступ в настройках")
}
}
return
}

// Репозитории
val authRepository = AuthRepository(RetrofitClient.authApiService)
val mapRepository = MapRepository(RetrofitClient.mapApiService)

// ViewModels
val authViewModel = AuthViewModel(authRepository)
val mapViewModel = MapViewModel(mapRepository)

NavHost(navController = navController, startDestination = "login") {
composable("login") {
Expand All @@ -40,5 +154,8 @@ fun EVRoutesApp() {
composable("register") {
RegisterScreen(viewModel = authViewModel, navController = navController)
}
composable("map") {
MapScreen(navController = navController, viewModel = mapViewModel)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.evroutes.data.model

data class LoginRequest(
val email: String,
val login: String,
val password: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.example.evroutes.data.model;


data class ChargingStationRequest(
val name: String,
val latitude: Double,
val longtitude: Double,
val connection_type: String,
val power_kw: Int
)

// Ответ со списком зарядных станций
data class ChargingStationsResponse(
val stations: List<ChargingStation>
)

// Модель зарядной станции
data class ChargingStation(
val id: String,
val name: String,
val latitude: Double,
val longitude: Double,
val address: String,
val connectorTypes: List<String>,
val power: Int, // кВт
val isAvailable: Boolean,
val price: Double,
val openingHours: String,
val rating: Double
)

data class RouteRequest(
val fromLatitude: Double,
val fromLongitude: Double,
val toLatitude: Double,
val toLongitude: Double,
val batteryLevel: Int, // процент заряда
val vehicleRange: Int // запас хода в км
)

// Оптимизированный маршрут
data class OptimizedRoute(
val totalDistance: Double, // км
val estimatedTime: Int, // минуты
val waypoints: List<RouteWaypoint>,
val chargingStops: List<ChargingStop>
)

// Точка маршрута
data class RouteWaypoint(
val latitude: Double,
val longitude: Double,
val distanceFromStart: Double, // км от начала маршрута
val estimatedTimeFromStart: Int // минуты от начала маршрута
)

// Остановка для зарядки
data class ChargingStop(
val station: ChargingStation,
val arrivalBatteryLevel: Int, // процент заряда при прибытии
val recommendedChargingTime: Int, // минуты
val departureBatteryLevel: Int // процент заряда при отъезде
)
Loading