Browse Source

add: two screens with descriptions of attractions and hotels have been created, the initial screen has been added - in development; update: updated navigation, route view model, changed and updated the display of many parts

unknown 1 week ago
parent
commit
51c96c56fa

+ 2 - 2
TripHelper/.idea/deploymentTargetSelector.xml

@@ -4,10 +4,10 @@
     <selectionStates>
       <SelectionState runConfigName="app">
         <option name="selectionMode" value="DROPDOWN" />
-        <DropdownSelection timestamp="2024-11-13T17:42:04.855787300Z">
+        <DropdownSelection timestamp="2024-11-20T10:30:23.949012400Z">
           <Target type="DEFAULT_BOOT">
             <handle>
-              <DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\mikam\.android\avd\Pixel_8_API_UpsideDownCakePrivacySandbox.avd" />
+              <DeviceId pluginId="LocalEmulator" identifier="path=C:\AndroidSettings\.android\avd\Pixel_8_API_34.avd" />
             </handle>
           </Target>
         </DropdownSelection>

+ 0 - 4
TripHelper/app/build.gradle.kts

@@ -90,8 +90,4 @@ dependencies {
     implementation(libs.androidx.navigation.compose)
 
     implementation (libs.ui)
-
-    implementation(libs.mapkit)
-    implementation(libs.mapkit.search)
-    implementation (libs.maps.mobile)
 }

+ 8 - 0
TripHelper/app/src/main/java/com/example/triphelper/model/FallingIcon.kt

@@ -0,0 +1,8 @@
+package com.example.triphelper.model
+
+data class FallingIcon(
+    val id: Int,
+    var x: Float, // Горизонтальное положение
+    var y: Float, // Вертикальное положение
+    val velocity: Float = 2f // Скорость падения
+)

+ 215 - 0
TripHelper/app/src/main/java/com/example/triphelper/view/RouteScreens/AttractionsDesc.kt

@@ -0,0 +1,215 @@
+package com.example.triphelper.view.RouteScreens
+
+import android.media.audiofx.AudioEffect.Descriptor
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavController
+import coil.compose.AsyncImagePainter
+import coil.compose.rememberAsyncImagePainter
+import coil.request.ImageRequest
+import com.example.triphelper.model.Attractions
+import com.example.triphelper.view.MainScreen.LawScreenViewModel
+import com.example.triphelper.view.style.StyleMainFone
+import com.example.triphelper.view.theme.Roboto
+import com.example.triphelper.view.theme.RobotoB
+import com.example.triphelper.view.theme.SeoulBold
+
+@Composable
+fun AttractionsDesc(navController: NavController, iconsRouteIsActivity: MutableState<Boolean>,idAttractions:Int, titleAttractions:String, viewModel: RouteViewModel = hiltViewModel()) {
+    iconsRouteIsActivity.value = true
+    val attractions by viewModel.attractions.collectAsState(initial = emptyList())
+
+    LaunchedEffect(key1 = viewModel.navigationTo) {
+        viewModel.navigationTo.collect { destination ->
+            destination?.let {
+                navController.navigate(destination)
+            }
+        }
+    }
+    Column(
+        modifier = Modifier
+            .fillMaxSize()
+            .background(Color.White),
+        verticalArrangement = Arrangement.Top,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        Column {
+            Text(
+                text = titleAttractions,
+                color = Color(0xFF510B3C),
+                fontSize = 28.sp,
+                fontFamily = SeoulBold,
+                fontWeight = FontWeight.Bold,
+                textAlign = TextAlign.Center,
+                modifier = Modifier.padding(top = 60.dp)
+            )
+        }
+        LaunchedEffect(Unit) {
+            viewModel.GetAttractions(idAttractions)
+        }
+        LazyColumn(
+            modifier = Modifier
+                .padding(top = 20.dp, bottom = 60.dp)
+                .fillMaxHeight(0.94f)
+        ) {
+            items(
+                attractions,
+                key = { attractions -> attractions.id },
+            ) { attractions ->
+                val imageState = rememberAsyncImagePainter(
+                    model = ImageRequest.Builder(LocalContext.current).data(attractions.photo)
+                        .size(coil.size.Size.ORIGINAL).build()
+                ).state
+                if (imageState is AsyncImagePainter.State.Error) {
+                    Box(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .height(200.dp),
+                        contentAlignment = Alignment.Center
+                    ) {
+                        CircularProgressIndicator()
+                    }
+                }
+                if (imageState is AsyncImagePainter.State.Success) {
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                    ) {
+                        Box(
+                            contentAlignment = Alignment.Center,
+                            modifier = Modifier.padding(bottom = 20.dp).fillMaxWidth()
+                        ) {
+                            Image(
+                                modifier = Modifier
+                                    .fillMaxWidth(0.9f)
+                                    .clip(RoundedCornerShape(10.dp)),
+                                painter = imageState.painter,
+                                contentDescription = "",
+                                contentScale = ContentScale.Crop,
+                                alignment = Alignment.Center
+                            )
+                        }
+                        Column(
+                            horizontalAlignment = Alignment.Start,
+                            verticalArrangement = Arrangement.spacedBy(20.dp),
+                            modifier = Modifier.padding(start = 20.dp).fillMaxWidth(0.9f)
+                        ) {
+                            Text(
+                                text = "Краткая история",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = attractions.history,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Адрес",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = attractions.address,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Как добраться",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = attractions.route,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Часы работы",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = attractions.schedule_more,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Стоимость",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = attractions.price,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                                modifier = Modifier
+                                    .padding(bottom = 40.dp)
+                            )
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+}

+ 284 - 0
TripHelper/app/src/main/java/com/example/triphelper/view/RouteScreens/HotelsDesc.kt

@@ -0,0 +1,284 @@
+package com.example.triphelper.view.RouteScreens
+
+import android.media.audiofx.AudioEffect.Descriptor
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavController
+import coil.compose.AsyncImagePainter
+import coil.compose.rememberAsyncImagePainter
+import coil.request.ImageRequest
+import com.example.triphelper.model.Attractions
+import com.example.triphelper.view.MainScreen.LawScreenViewModel
+import com.example.triphelper.view.style.StyleMainFone
+import com.example.triphelper.view.theme.Roboto
+import com.example.triphelper.view.theme.RobotoB
+import com.example.triphelper.view.theme.SeoulBold
+
+@Composable
+fun HotelsDesc(navController: NavController, iconsRouteIsActivity: MutableState<Boolean>,idHotel:Int, titleHotel:String, viewModel: RouteViewModel = hiltViewModel()) {
+    iconsRouteIsActivity.value = true
+    val hotels by viewModel.hotels.collectAsState(initial = emptyList())
+
+    LaunchedEffect(key1 = viewModel.navigationTo) {
+        viewModel.navigationTo.collect { destination ->
+            destination?.let {
+                navController.navigate(destination)
+            }
+        }
+    }
+    Column(
+        modifier = Modifier
+            .fillMaxSize()
+            .background(Color.White),
+        verticalArrangement = Arrangement.Top,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        Column {
+            Text(
+                text = titleHotel,
+                color = Color(0xFF510B3C),
+                fontSize = 28.sp,
+                fontFamily = SeoulBold,
+                fontWeight = FontWeight.Bold,
+                textAlign = TextAlign.Center,
+                modifier = Modifier.padding(top = 60.dp)
+            )
+        }
+        LaunchedEffect(Unit) {
+            viewModel.GetHotel(idHotel)
+        }
+        LazyColumn(
+            modifier = Modifier
+                .padding(top = 20.dp, bottom = 60.dp)
+                .fillMaxHeight(0.94f)
+        ) {
+            items(
+                hotels,
+                key = { hotels -> hotels.id },
+            ) { hotels ->
+                val imageStateHotel = rememberAsyncImagePainter(
+                    model = ImageRequest.Builder(LocalContext.current).data(hotels.photo_hotel)
+                        .size(coil.size.Size.ORIGINAL).build()
+                ).state
+                val imageStateRoom = rememberAsyncImagePainter(
+                    model = ImageRequest.Builder(LocalContext.current).data(hotels.photo_room)
+                        .size(coil.size.Size.ORIGINAL).build()
+                ).state
+                val imageStateInterior = rememberAsyncImagePainter(
+                    model = ImageRequest.Builder(LocalContext.current).data(hotels.photo_interior)
+                        .size(coil.size.Size.ORIGINAL).build()
+                ).state
+                if (imageStateHotel is AsyncImagePainter.State.Error || imageStateRoom is AsyncImagePainter.State.Error || imageStateInterior is AsyncImagePainter.State.Error) {
+                    Box(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .height(200.dp),
+                        contentAlignment = Alignment.Center
+                    ) {
+                        CircularProgressIndicator()
+                    }
+                }
+                if (imageStateHotel is AsyncImagePainter.State.Success && imageStateRoom is AsyncImagePainter.State.Success && imageStateInterior is AsyncImagePainter.State.Success) {
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                    ) {
+                        Box(
+                            contentAlignment = Alignment.Center,
+                            modifier = Modifier.padding(bottom = 20.dp).fillMaxWidth()
+                        ) {
+                            Image(
+                                modifier = Modifier
+                                    .fillMaxWidth(0.9f)
+                                    .height(190.dp)
+                                    .clip(RoundedCornerShape(10.dp)),
+                                painter = imageStateHotel.painter,
+                                contentDescription = "",
+                                contentScale = ContentScale.Crop,
+                                alignment = Alignment.Center
+                            )
+                        }
+                        Column(
+                            horizontalAlignment = Alignment.Start,
+                            verticalArrangement = Arrangement.spacedBy(20.dp),
+                            modifier = Modifier.padding(start = 20.dp).fillMaxWidth(0.9f)
+                        ) {
+                            Text(
+                                text = "Адрес",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = hotels.address,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Основная информация",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = hotels.basic_info,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Интерьер",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Box(
+                                contentAlignment = Alignment.Center,
+                                modifier = Modifier.fillMaxWidth()
+                            ) {
+                                Image(
+                                    modifier = Modifier
+                                        .fillMaxWidth()
+                                        .height(190.dp)
+                                        .clip(RoundedCornerShape(10.dp)),
+                                    painter = imageStateInterior.painter,
+                                    contentDescription = "",
+                                    contentScale = ContentScale.Crop,
+                                    alignment = Alignment.Center
+                                )
+                            }
+                            Text(
+                                text = hotels.interior,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Комнаты",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Box(
+                                contentAlignment = Alignment.Center,
+                                modifier = Modifier.fillMaxWidth()
+                            ) {
+                                Image(
+                                    modifier = Modifier
+                                        .fillMaxWidth()
+                                        .height(190.dp)
+                                        .clip(RoundedCornerShape(10.dp)),
+                                    painter = imageStateRoom.painter,
+                                    contentDescription = "",
+                                    contentScale = ContentScale.Crop,
+                                    alignment = Alignment.Center
+                                )
+                            }
+                            Text(
+                                text = hotels.rooms,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start,
+                            )
+                            Text(
+                                text = "Цены",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = hotels.price,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = "Доп услуги",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = hotels.services,
+                                color = Color(0xFF000000),
+                                fontSize = 20.sp,
+                                fontFamily = Roboto,
+                                textAlign = TextAlign.Start
+                            )
+                            Text(
+                                text = "Заезд/Выезд",
+                                color = Color(0xFF510B3C),
+                                fontSize = 26.sp,
+                                fontFamily = SeoulBold,
+                                fontWeight = FontWeight.Bold,
+                                textAlign = TextAlign.Start
+                            )
+//                            Text(
+//                                text = hotels.,
+//                                color = Color(0xFF000000),
+//                                fontSize = 20.sp,
+//                                fontFamily = Roboto,
+//                                textAlign = TextAlign.Start,
+//                                modifier = Modifier
+//                                    .padding(bottom = 40.dp)
+//                            )
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+}

+ 124 - 11
TripHelper/app/src/main/java/com/example/triphelper/view/RouteScreens/RouteViewModel.kt

@@ -8,6 +8,8 @@ import com.example.triphelper.domain.Constants
 import com.example.triphelper.model.Attractions
 import com.example.triphelper.model.City
 import com.example.triphelper.model.Country
+import com.example.triphelper.model.Hotels
+import com.example.triphelper.model.Metro
 import com.example.triphelper.model.Organization_of_tours
 import com.example.triphelper.model.Rules
 import com.example.triphelper.model.Tours
@@ -58,10 +60,15 @@ class RouteViewModel @Inject constructor() : ViewModel() {
     private var _attractions: MutableStateFlow<List<Attractions>> = MutableStateFlow(listOf())
     val attractions: StateFlow<List<Attractions>> = _attractions.asStateFlow()
 
+    private var _hotels: MutableStateFlow<List<Hotels>> = MutableStateFlow(listOf())
+    val hotels: StateFlow<List<Hotels>> = _hotels.asStateFlow()
+
+    private var _metro: MutableStateFlow<List<Metro>> = MutableStateFlow(listOf())
+    val metro: StateFlow<List<Metro>> = _metro.asStateFlow()
+
     fun getCountry() {
         viewModelScope.launch {
             try {
-                GetAttractions(1, "Сеул")
                 withContext(Dispatchers.IO) {
                     val response = Constants.supabase
                         .from("country")
@@ -163,26 +170,132 @@ class RouteViewModel @Inject constructor() : ViewModel() {
         }
     }
 
-    suspend fun GetAttractions(numberTour: Int, titleCity:String) {
+
+    fun GetOrgTour(numberTour: Int, titleCity:String) {
         viewModelScope.launch {
-            withContext(Dispatchers.IO) {
-                val columns = Columns.raw("""
+            try {
+                withContext(Dispatchers.IO) {
+                    val columns = Columns.raw(
+                        """
                     id,
                     tours!inner(id,title),
                     attractions!inner(id,city!inner(id,country!inner(id,title,flag),title),currency!inner(id,country!inner(id,title,flag),title),name,visiting,work_schedule,price_showing,photo,history,address,route,schedule_more,price,coordinates),
                     hotels!inner(id,city!inner(id,country!inner(id,title,flag),title),rating,quantity_of_rooms,floors,name,photo_hotel,address,basic_info,interior,photo_interior,rooms,photo_room,services,price,coordinates),
                     restaurants!inner(id,city!inner(id,country!inner(id,title,flag),title),currency!inner(id,country!inner(id,title,flag),title),name,work_schedule,phone,photo,address,basic_info,interior,recommendations,price,average_check,coordinates)
+                """.trimIndent()
+                    )
+                    val responce = Constants.supabase.from("organization_of_tours").select(
+                        columns = columns
+                    ) {
+                        filter {
+                            eq("attractions.city.title", titleCity)
+                        }
+                    }.decodeList<Organization_of_tours>()
+                    val new_responce = responce.filter { it.tours.id == numberTour }
+                    _orgTour.value = new_responce
+                    Log.i("orgTour", titleCity)
+                }
+            }catch (e:Exception){
+                Log.e("orgTour", "Error")
+            }
+        }
+    }
+    fun GetAttractions(idAttractions: Int){
+        viewModelScope.launch {
+            try {
+                withContext(Dispatchers.IO) {
+                    val columns = Columns.raw("""
+                    id,
+                    city!inner(id,country!inner(id,title,flag),title),
+                    currency!inner(id,country!inner(id,title,flag),title),
+                    name,
+                    visiting,
+                    work_schedule,
+                    price_showing,
+                    photo,
+                    history,
+                    address,
+                    route,
+                    schedule_more,
+                    price,
+                    coordinates
+                """.trimIndent()
+                    )
+                    val responce = Constants.supabase.from("attractions").select(
+                        columns = columns
+                    ) {
+                        filter {
+                            eq("id", idAttractions)
+                        }
+                    }.decodeList<Attractions>()
+                    _attractions.value = responce
+                    Log.i("AttractDesc", "Success")
+                }
+            }catch (e:Exception){
+                Log.e("AttractDesc", "Error")
+            }
+        }
+    }
+    fun GetHotel(idHotel: Int){
+        viewModelScope.launch {
+            try {
+                withContext(Dispatchers.IO) {
+                    val columns = Columns.raw("""
+                    id,
+                    city!inner(id,country!inner(id,title,flag),title),
+                    rating,
+                    quantity_of_rooms,
+                    floors,
+                    name,
+                    photo_hotel,
+                    address,
+                    basic_info,
+                    interior,
+                    photo_interior,
+                    rooms,
+                    photo_room,
+                    services,
+                    price,
+                    coordinates
+                """.trimIndent()
+                    )
+                    val responce = Constants.supabase.from("hotels").select(
+                        columns = columns
+                    ) {
+                        filter {
+                            eq("id", idHotel)
+                        }
+                    }.decodeList<Hotels>()
+                    _hotels.value = responce
+                    Log.i("HotelsDesc", "Success")
+                }
+            }catch (e:Exception){
+                Log.e("HotelsDesc", "Error")
+            }
+        }
+    }
+    fun GetMetro(titleCity: String){
+        viewModelScope.launch {
+            withContext(Dispatchers.IO){
+                val columns = Columns.raw("""
+                    id,
+                    city!inner(id, country!inner(id, title, flag), title),
+                    photo
                 """.trimIndent())
-                val responce = Constants.supabase.from("organization_of_tours").select(
+                val responce = Constants.supabase.from("metro").select(
                     columns = columns
-                ) {
+                ){
                     filter {
-                            eq("tours.id", numberTour)
-                            eq("attractions.city.title", titleCity)
+                        eq("city.title", titleCity)
                     }
-                }.decodeList<Organization_of_tours>()
-                _orgTour.value = responce
-                Log.i("tours", "${_orgTour.value}")
+                }.decodeList<Metro>()
+                _metro.value = responce
+                if (responce.isNullOrEmpty()) {
+                    Log.i("metro", "No metro data found for $titleCity")
+                } else {
+                    _metro.value = responce
+                    Log.i("metro", "Success")
+                }
             }
         }
     }

+ 9 - 6
TripHelper/app/src/main/java/com/example/triphelper/view/RouteScreens/Tours.kt

@@ -51,6 +51,7 @@ import coil.request.ImageRequest
 import com.example.testirovanye_supabase.R
 import com.example.triphelper.view.style.AttractionsLazy
 import com.example.triphelper.view.style.HotelsLazy
+import com.example.triphelper.view.style.MetroLazy
 import com.example.triphelper.view.style.RestaurantsLazy
 import com.example.triphelper.view.style.StyleMainFone
 import com.example.triphelper.view.theme.Roboto
@@ -68,6 +69,7 @@ fun Tours(navController: NavController, iconsRouteIsActivity: MutableState<Boole
     var restouranceColumn by remember { mutableStateOf(false) }
     var metroColumn by remember { mutableStateOf(false) }
     val orgTour by viewModel.orgTour.collectAsState(initial = emptyList())
+    val metro by viewModel.metro.collectAsState(initial = emptyList())
 
 
     LaunchedEffect(key1 = viewModel.navigationTo) {
@@ -80,7 +82,7 @@ fun Tours(navController: NavController, iconsRouteIsActivity: MutableState<Boole
     LaunchedEffect(Unit) {
         viewModel.getNameToure(numberTour.toInt())
     }
-    viewModel.getCountry()
+    viewModel.GetOrgTour(numberTour.toInt(),titleCity)
     StyleMainFone()
     Column(
         modifier = Modifier
@@ -221,19 +223,20 @@ fun Tours(navController: NavController, iconsRouteIsActivity: MutableState<Boole
             }
         }
         LaunchedEffect(Unit) {
-            viewModel.GetAttractions(numberTour.toInt(), titleCity)
+            viewModel.GetOrgTour(numberTour.toInt(), titleCity)
+            viewModel.GetMetro(titleCity)
         }
         if (attarctionsColumn) {
-            AttractionsLazy(orgTour)
+            AttractionsLazy(navController,orgTour)
         }
         if (hotelColumn) {
-            HotelsLazy(orgTour)
+            HotelsLazy(navController,orgTour)
         }
         if(restouranceColumn){
-            RestaurantsLazy(orgTour)
+            RestaurantsLazy(navController,orgTour)
         }
         if(metroColumn){
-
+            MetroLazy(metro)
         }
     }
 }

+ 86 - 0
TripHelper/app/src/main/java/com/example/triphelper/view/SplashScreen/SplashScreen.kt

@@ -0,0 +1,86 @@
+package com.example.triphelper.view.SplashScreen
+
+import android.annotation.SuppressLint
+import android.content.res.Configuration
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.expandHorizontally
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.shrinkHorizontally
+import androidx.compose.animation.slideInHorizontally
+import androidx.compose.animation.slideOutHorizontally
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.res.imageResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.example.testirovanye_supabase.R
+import com.example.triphelper.view.navigation.NavigationRoutes
+import kotlinx.coroutines.delay
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.runtime.getValue
+
+@SuppressLint("RememberReturnType")
+@Composable
+fun SplashScreen(navController: NavHostController) {
+    val configuration = LocalConfiguration.current
+    if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+        val infiniteTransition = rememberInfiniteTransition()
+        val offsetY by infiniteTransition.animateFloat(
+            initialValue = 0f,
+            targetValue = 1000f, // Значение смещения вниз
+            animationSpec = infiniteRepeatable(
+                animation = tween(durationMillis = 1000, easing = FastOutSlowInEasing),
+                repeatMode = RepeatMode.Restart // Анимация будет перезапускаться
+            ), label = ""
+        )
+
+        LaunchedEffect(key1 = true) {
+            delay(1000L) // Задержка перед переходом на другой экран (на всякий случай)
+            navController.navigate(NavigationRoutes.CH_LOC) {
+                popUpTo(NavigationRoutes.SPLASH) { inclusive = true }
+            }
+        }
+
+        Box(
+            modifier = Modifier
+                .fillMaxSize()
+                .background(Color.White),
+            contentAlignment = Alignment.Center
+        ) {
+            Image(
+                painter = painterResource(id = R.drawable.logoth),
+                contentDescription = "",
+                modifier = Modifier
+                    .size(200.dp)
+                    .offset(y = offsetY.dp) //  Анимация смещения по Y
+            )
+        }
+    }
+}

+ 0 - 3
TripHelper/app/src/main/java/com/example/triphelper/view/mainActivity/MainActivity.kt

@@ -13,8 +13,6 @@ import androidx.navigation.compose.rememberNavController
 import com.example.studybuddy.view.panels.bottombar.BottomBar
 import com.example.studybuddy.view.panels.topbar.TopBarApp
 import com.example.triphelper.view.navigation.Navigation
-import com.example.triphelper.view.style.StyleMainFone
-import com.yandex.mapkit.MapKitFactory
 import dagger.hilt.android.AndroidEntryPoint
 
 @AndroidEntryPoint
@@ -23,7 +21,6 @@ class MainActivity : ComponentActivity() {
     @RequiresApi(Build.VERSION_CODES.O)
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        MapKitFactory.setApiKey("9e42329a-2735-445f-ad60-32a56c59bce3")
         setContent {
             val controller = rememberNavController()
             val barsIsVisible = remember { mutableStateOf(false) }

+ 36 - 1
TripHelper/app/src/main/java/com/example/triphelper/view/navigation/Navigation.kt

@@ -13,9 +13,12 @@ import com.example.triphelper.view.LawScreen.DescriptionLaws
 import com.example.triphelper.view.MainScreen.LawScreen
 import com.example.triphelper.view.MainScreen.MainScreen
 import com.example.triphelper.view.Registration.Registration
+import com.example.triphelper.view.RouteScreens.AttractionsDesc
 import com.example.triphelper.view.RouteScreens.ChoiceLocation
 import com.example.triphelper.view.RouteScreens.ChoiceTour
+import com.example.triphelper.view.RouteScreens.HotelsDesc
 import com.example.triphelper.view.RouteScreens.Tours
+import com.example.triphelper.view.SplashScreen.SplashScreen
 
 @RequiresApi(Build.VERSION_CODES.O)
 @Composable
@@ -23,8 +26,12 @@ fun Navigation(controller: NavHostController, barsIsVisible: MutableState<Boolea
                iconsLawIsActivity: MutableState<Boolean>, iconsProfileIsActivity: MutableState<Boolean>,
                iconsAdviceIsActivity: MutableState<Boolean>,iconsMainIsActivity: MutableState<Boolean>, iconsRoutsIsActivity: MutableState<Boolean>) {
     NavHost(navController = controller,
-        startDestination = NavigationRoutes.CH_LOC)
+        startDestination = NavigationRoutes.SPLASH)
     {
+        composable( NavigationRoutes.SPLASH){
+            barsIsVisible.value = false
+            SplashScreen(controller)
+        }
         composable( NavigationRoutes.AUTH){
             barsIsVisible.value = false
             Auth(controller)
@@ -100,5 +107,33 @@ fun Navigation(controller: NavHostController, barsIsVisible: MutableState<Boolea
                 Tours(controller, iconsRoutsIsActivity, titleCity, numberToure)
             }
         }
+        composable(route =  "${NavigationRoutes.ATT_DESC}/{idAttractions}/{titleAttractions}"){
+                backStackEntry ->
+            val idAttractions = backStackEntry.arguments?.getString("idAttractions")
+            val titleAttractions = backStackEntry.arguments?.getString("titleAttractions")
+            barsIsVisible.value = true
+            iconsLawIsActivity.value = false
+            iconsAdviceIsActivity.value = false
+            iconsProfileIsActivity.value = false
+            iconsMainIsActivity.value = false
+            iconsRoutsIsActivity.value = false
+            if (idAttractions != null && titleAttractions != null) {
+                AttractionsDesc(controller, iconsRoutsIsActivity, idAttractions.toInt(), titleAttractions)
+            }
+        }
+        composable(route =  "${NavigationRoutes.HOTEL_DESC}/{idHotels}/{titleHotels}"){
+                backStackEntry ->
+            val idHotels = backStackEntry.arguments?.getString("idHotels")
+            val titleHotels = backStackEntry.arguments?.getString("titleHotels")
+            barsIsVisible.value = true
+            iconsLawIsActivity.value = false
+            iconsAdviceIsActivity.value = false
+            iconsProfileIsActivity.value = false
+            iconsMainIsActivity.value = false
+            iconsRoutsIsActivity.value = false
+            if (idHotels != null && titleHotels != null) {
+                HotelsDesc(controller, iconsRoutsIsActivity, idHotels.toInt(), titleHotels)
+            }
+        }
     }
 }

+ 2 - 0
TripHelper/app/src/main/java/com/example/triphelper/view/navigation/NavigationRoutes.kt

@@ -10,4 +10,6 @@ object NavigationRoutes {
     const val CH_LOC = "choicelocation"
     const val  CH_TOUR = "choicetour"
     const val TOURS = "tours"
+    const val ATT_DESC = "attractionsdesc"
+    const val HOTEL_DESC = "hotelsdesc"
 }

+ 75 - 15
TripHelper/app/src/main/java/com/example/triphelper/view/style/LazyColumnStyle.kt

@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
@@ -17,9 +18,12 @@ import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
 import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.Icon
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -27,6 +31,7 @@ import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
@@ -35,15 +40,18 @@ import androidx.navigation.NavController
 import coil.compose.AsyncImagePainter
 import coil.compose.rememberAsyncImagePainter
 import coil.request.ImageRequest
+import com.example.testirovanye_supabase.R
 import com.example.triphelper.model.Attractions
+import com.example.triphelper.model.Metro
 import com.example.triphelper.model.Organization_of_tours
 import com.example.triphelper.model.Restaurants
 import com.example.triphelper.view.RouteScreens.RouteViewModel
+import com.example.triphelper.view.navigation.NavigationRoutes
 import com.example.triphelper.view.theme.Roboto
 import com.example.triphelper.view.theme.RobotoB
 
 @Composable
-fun AttractionsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
+fun AttractionsLazy(navController: NavController,orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
     LazyColumn(
         modifier = Modifier.fillMaxHeight(0.84f)
     ) {
@@ -82,6 +90,9 @@ fun AttractionsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewMode
                         Modifier
                             .fillMaxWidth()
                             .fillMaxHeight()
+                            .clickable {
+                                navController.navigate("${NavigationRoutes.ATT_DESC}/${orgTour.attractions.id}/${orgTour.attractions.name}")
+                            }
                             .clip(RoundedCornerShape(15.dp))
                             .background(Color.White)
                     ) {
@@ -91,7 +102,9 @@ fun AttractionsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewMode
                                     .width(140.dp)
                                     .fillMaxHeight()
                                     .clip(RoundedCornerShape(15.dp))
-                                    .clickable {},
+                                    .clickable {
+                                        navController.navigate("${NavigationRoutes.ATT_DESC}/${orgTour.attractions.id}/${orgTour.attractions.name}")
+                                    },
                                 painter = imageState.painter,
                                 contentDescription = "",
                                 contentScale = ContentScale.Crop
@@ -188,7 +201,7 @@ fun AttractionsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewMode
 }
 
 @Composable
-fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
+fun HotelsLazy(navController: NavController,orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
     LazyColumn(
         modifier = Modifier.fillMaxHeight(0.84f)
     ) {
@@ -227,6 +240,9 @@ fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = h
                         Modifier
                             .fillMaxWidth()
                             .fillMaxHeight()
+                            .clickable {
+                                navController.navigate("${NavigationRoutes.HOTEL_DESC}/${orgTour.hotels.id}/${orgTour.hotels.name}")
+                            }
                             .clip(RoundedCornerShape(15.dp))
                             .background(Color.White)
                     ) {
@@ -236,7 +252,9 @@ fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = h
                                     .width(140.dp)
                                     .fillMaxHeight()
                                     .clip(RoundedCornerShape(15.dp))
-                                    .clickable {},
+                                    .clickable {
+                                        navController.navigate("${NavigationRoutes.HOTEL_DESC}/${orgTour.hotels.id}/${orgTour.hotels.name}")
+                                    },
                                 painter = imageState.painter,
                                 contentDescription = "",
                                 contentScale = ContentScale.Crop
@@ -266,7 +284,10 @@ fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = h
                                     Column(
                                         verticalArrangement = Arrangement.spacedBy(10.dp)
                                     ) {
-                                        Row {
+                                        Row(
+                                            verticalAlignment = Alignment.CenterVertically,
+                                            modifier = Modifier.height(20.dp)
+                                        ) {
                                             Text(
                                                 text = "Рейтинг: ",
                                                 color = Color(0xFF510B3C),
@@ -274,13 +295,20 @@ fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = h
                                                 fontFamily = RobotoB,
                                                 textAlign = TextAlign.Center
                                             )
-                                            Text(
-                                                text = orgTour.hotels.rating.toString(),
-                                                color = Color(0xFF510B3C),
-                                                fontSize = 14.sp,
-                                                fontFamily = Roboto,
-                                                textAlign = TextAlign.Center
-                                            )
+                                            Row(
+                                                verticalAlignment = Alignment.CenterVertically
+                                            ){
+                                                (0 until 5).map { IndexedValue(it, it < orgTour.hotels.rating) }
+                                                    .forEach { (index, filled) ->
+                                                        Image(
+                                                            painter = painterResource(if (filled) R.drawable.star_active else R.drawable.star_notactive),
+                                                            contentDescription = if (filled) "Filled Star" else "Outlined Star",
+                                                            modifier = Modifier.size(20.dp),
+                                                            contentScale = ContentScale.Fit,
+                                                            alignment = Alignment.Center
+                                                        )
+                                                    }
+                                            }
                                         }
                                         Row {
                                             Text(
@@ -328,7 +356,7 @@ fun HotelsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = h
 }
 
 @Composable
-fun RestaurantsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
+fun RestaurantsLazy(navController: NavController,orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
     LazyColumn(
         modifier = Modifier.fillMaxHeight(0.84f)
     ) {
@@ -467,6 +495,38 @@ fun RestaurantsLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewMode
 }
 
 @Composable
-fun MetroLazy(orgTour:List<Organization_of_tours>,viewModel: RouteViewModel = hiltViewModel()){
-
+fun MetroLazy(metro:List<Metro>, viewModel: RouteViewModel = hiltViewModel()){
+    LazyColumn(
+        modifier = Modifier.fillMaxHeight(0.84f)
+    ) {
+        items(
+            metro,
+            key = { metro -> metro.id },
+        ) { metro ->
+            val imageState = rememberAsyncImagePainter(
+                model = ImageRequest.Builder(LocalContext.current).data(metro.photo)
+                    .size(coil.size.Size.ORIGINAL).build()
+            ).state
+            if (imageState is AsyncImagePainter.State.Error) {
+                Box(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .height(200.dp),
+                    contentAlignment = Alignment.Center
+                ) {
+                    CircularProgressIndicator()
+                }
+            }
+            if (imageState is AsyncImagePainter.State.Success) {
+                Image(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .clip(RoundedCornerShape(5.dp)),
+                    painter = imageState.painter,
+                    contentDescription = "",
+                    contentScale = ContentScale.Crop
+                )
+            }
+        }
+    }
 }

+ 11 - 0
TripHelper/app/src/main/res/drawable/star_active.xml

@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="20"
+    android:viewportHeight="20">
+  <path
+      android:pathData="M10.402,15.439L10,15.184L9.598,15.439L4.943,18.397L6.192,12.761L6.286,12.337L5.965,12.045L1.766,8.215L7.256,7.725L7.713,7.684L7.885,7.258L10,2.007L12.115,7.258L12.287,7.684L12.744,7.725L18.234,8.215L14.035,12.045L13.714,12.337L13.808,12.761L15.057,18.397L10.402,15.439Z"
+      android:strokeWidth="1.5"
+      android:fillColor="#FFC804"
+      android:strokeColor="#510B3C"/>
+</vector>

+ 11 - 0
TripHelper/app/src/main/res/drawable/star_notactive.xml

@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="20"
+    android:viewportHeight="20">
+  <path
+      android:pathData="M10.402,15.439L10,15.184L9.598,15.439L4.943,18.397L6.192,12.761L6.286,12.337L5.965,12.045L1.766,8.215L7.256,7.725L7.713,7.684L7.885,7.258L10,2.007L12.115,7.258L12.287,7.684L12.744,7.725L18.234,8.215L14.035,12.045L13.714,12.337L13.808,12.761L15.057,18.397L10.402,15.439Z"
+      android:strokeWidth="1.5"
+      android:fillColor="#00000000"
+      android:strokeColor="#510B3C"/>
+</vector>