Procházet zdrojové kódy

App: вёрстка страницы об игре, настройка избранных, вывод логина

Blueris před 3 dny
rodič
revize
783da3baa1

+ 8 - 0
OscellaMobile/.idea/deploymentTargetSelector.xml

@@ -4,6 +4,14 @@
     <selectionStates>
       <SelectionState runConfigName="Unnamed">
         <option name="selectionMode" value="DROPDOWN" />
+        <DropdownSelection timestamp="2024-11-21T18:01:34.284318100Z">
+          <Target type="DEFAULT_BOOT">
+            <handle>
+              <DeviceId pluginId="PhysicalDevice" identifier="serial=3f99f7b3" />
+            </handle>
+          </Target>
+        </DropdownSelection>
+        <DialogSelection />
       </SelectionState>
     </selectionStates>
   </component>

+ 1 - 0
OscellaMobile/app/build.gradle.kts

@@ -87,6 +87,7 @@ dependencies {
     implementation ("androidx.compose.material:material:1.3.0") // для Material Design компонентов
     implementation ("androidx.compose.ui:ui-tooling-preview:1.3.0") // для предварительного просмотра
     implementation ("androidx.activity:activity-compose:1.6.0")
+    implementation ("com.pierfrancescosoffritti.androidyoutubeplayer:core:11.1.0")
 
     implementation(libs.coil.compose)
 

+ 9 - 0
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Favorite.kt

@@ -0,0 +1,9 @@
+package com.example.oscellamobile.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Favorite(
+    val id_game: Int,
+    val id_user: Int
+)

+ 3 - 2
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Game.kt

@@ -13,7 +13,8 @@ data class Game(
     val favourites: Int?,
     val age_rating: Int?,
     val link_torrent: String?,
-    val link_oficial: String?,
+    val link_oficial: String,
     val short_description: String,
-    val genre: Int
+    val genre: Int,
+    val video: String?
 )

+ 10 - 0
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Game_Cloud.kt

@@ -0,0 +1,10 @@
+package com.example.oscellamobile.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Game_Cloud(
+    val id: Int,
+    val game: Int,
+    val cloud: Int
+)

+ 14 - 0
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Minimum_system_requirements.kt

@@ -0,0 +1,14 @@
+package com.example.oscellamobile.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Minimum_system_requirements(
+    val id: Int,
+    val OS: String?,
+    val processor: String?,
+    val RAM: String?,
+    val graphic_card: String?,
+    val free_space: String?,
+    val id_game: Int
+)

+ 14 - 0
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Recommended_system_requirements.kt

@@ -0,0 +1,14 @@
+package com.example.oscellamobile.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Recommended_system_requirements(
+    val id: Int,
+    val OS: String?,
+    val processor: String?,
+    val RAM: String?,
+    val graphic_card: String?,
+    val free_space: String?,
+    val id_game: Int
+)

+ 10 - 0
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Screnshot.kt

@@ -0,0 +1,10 @@
+package com.example.oscellamobile.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Screnshot(
+    val id: Int,
+    val game: Int,
+    val picture: String
+)

+ 0 - 1
OscellaMobile/app/src/main/java/com/example/oscellamobile/models/Users.kt

@@ -7,5 +7,4 @@ data class Users(
     val id: Int,
     val user: String,
     val login: String,
-    val code: Int
 )

+ 439 - 39
OscellaMobile/app/src/main/java/com/example/oscellamobile/screens/AboutGame.kt

@@ -1,37 +1,31 @@
 package com.example.oscellamobile.screens
 
+import android.graphics.Picture
 import android.util.Log
-import androidx.compose.foundation.BorderStroke
+import android.webkit.WebView
+import android.webkit.WebViewClient
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.snapping.SnapPosition
 import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 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.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyRow
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
+import androidx.compose.foundation.text.ClickableText
 import androidx.compose.material3.Card
-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.SideEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -39,22 +33,19 @@ import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RadialGradientShader
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.Shadow
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalUriHandler
 import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.text.font.Font
-import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.buildAnnotatedString
 import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import androidx.compose.ui.viewinterop.AndroidView
 import androidx.navigation.NavHostController
 import coil.compose.rememberAsyncImagePainter
 import com.example.oscellamobile.domain.utlis.Constant
@@ -64,28 +55,37 @@ import io.github.jan.supabase.postgrest.from
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.withContext
-import kotlin.math.cos
-import kotlin.math.sin
 import com.example.oscellamobile.R
-import com.example.oscellamobile.models.Company
 import coil.compose.AsyncImagePainter
-import coil.compose.rememberAsyncImagePainter
+import coil.compose.rememberImagePainter
 import coil.request.ImageRequest
 import coil.size.Size
-import com.example.oscellamobile.models.Age_rating
-import com.example.oscellamobile.models.Basic_labels
-import com.example.oscellamobile.models.Genre
-import com.example.oscellamobile.models.Label
-import org.intellij.lang.annotations.JdkConstants
+import com.example.oscellamobile.models.Game_Cloud
+import com.example.oscellamobile.models.Minimum_system_requirements
+import com.example.oscellamobile.models.Recommended_system_requirements
+import com.example.oscellamobile.models.Screnshot
+import com.example.oscellamobile.models.Сloud_gaming
+import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
 
 @Composable
 fun AboutGame(navController: NavHostController, id: Int) {
     var games by remember { mutableStateOf<List<Game>>(listOf()) }
+    var min by remember{mutableStateOf<List<Minimum_system_requirements>>(listOf())}
+    var rec by remember{mutableStateOf<List<Recommended_system_requirements>>(listOf())}
+    var cloudgame by remember{mutableStateOf<List<Game_Cloud>>(listOf())}
+    var cloud by remember{mutableStateOf<List<Сloud_gaming>>(listOf())}
+    var screen by remember { mutableStateOf<List<Screnshot>>(listOf())}
 
     LaunchedEffect(Unit) {
         withContext(Dispatchers.IO) {
             try {
                 games = Constant.supabase.from("Game").select().decodeList<Game>()
+                min = Constant.supabase.from("Minimum_system_requirements").select().decodeList<Minimum_system_requirements>()
+                rec = Constant.supabase.from("Recommended_system_requirements").select().decodeList<Recommended_system_requirements>()
+                cloudgame = Constant.supabase.from("Game_Cloud").select().decodeList<Game_Cloud>()
+                cloud = Constant.supabase.from("Сloud_gaming").select().decodeList<Сloud_gaming>()
+                screen = Constant.supabase.from("Screnshot").select().decodeList<Screnshot>()
+
                 games.forEach { Game ->
                     Log.d("C", Game.name_game)
                 }
@@ -95,22 +95,422 @@ fun AboutGame(navController: NavHostController, id: Int) {
         }
     }
 
-    val filteredGames = games.filter { it.id == id}
+    val filteredGames = games.filter { it.id == id }
+
+    val systemUiController = rememberSystemUiController()
+
+    LaunchedEffect(Unit) {
+        systemUiController.isStatusBarVisible = false
+        delay(5000)
+        systemUiController.isStatusBarVisible = false
+    }
+
+    Canvas(
+        modifier = Modifier
+            .fillMaxWidth()
+            .fillMaxHeight()
+    ) {
+        val gradient = Brush.linearGradient(
+            colors = listOf(
+                Color(0xFFFF9F1C),
+                Color(0xFFE71D36)
+            ),
+            start = Offset(size.width, 1200f),
+            end = Offset(150f, size.height)
+        )
 
-    LazyColumn {
-        items(
-            filteredGames,
-            key = { game -> game.id }
-        ) { game ->
-            GameItem(game)
+        drawRect(brush = gradient)
+    }
+
+    Column(
+        modifier = Modifier
+            .fillMaxWidth()
+            .fillMaxHeight()
+    ) {
+        Spacer(modifier = Modifier.height(10.dp))
+        Row {
+            Spacer(modifier = Modifier.width(13.dp))
+            Text(text = "Osccela", fontSize = 40.sp, fontFamily = kdamFontFamily)
+            Spacer(modifier = Modifier.width(145.dp))
+            Image(
+                painter = painterResource(id = R.drawable.personall),
+                contentDescription = "Описание изображения",
+                modifier = Modifier.size(90.dp)
+            )
+        }
+
+        LazyColumn {
+            items(
+                filteredGames,
+                key = { game -> game.id }
+            ) { game ->
+                GameItem(
+                    game = game,
+                    min = min,
+                    rec = rec,
+                    gamecloud = cloudgame,
+                    cloud = cloud,
+                    screen = screen
+                )
+            }
+        }
+    }
+}
+@Composable
+fun GameItem(
+    game: Game,
+    min: List<Minimum_system_requirements>,
+    rec: List<Recommended_system_requirements>,
+    gamecloud: List<Game_Cloud>,
+    cloud: List<Сloud_gaming>,
+    screen: List<Screnshot>
+) {
+    val imageState = rememberAsyncImagePainter(
+        model = ImageRequest.Builder(LocalContext.current).data(game.picture)
+            .size(Size.ORIGINAL).build()
+    ).state
+
+    Card(
+        Modifier.width(400.dp)
+            .padding(10.dp, 10.dp, 10.dp, 10.dp)
+            .background(color = Color(0xFFFDFFFC), shape = RoundedCornerShape(20.dp)),
+    )
+    {
+        Column(
+            modifier = Modifier.fillMaxWidth()
+        ) {
+            Column(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalAlignment = Alignment.CenterHorizontally
+            ) {
+                Text(
+                    game.name_game,
+                    textAlign = TextAlign.Center,
+                    fontFamily = kdamFontFamily,
+                    fontSize = 30.sp,
+                    color = Color(0xFF7F807E)
+                )
+                Spacer(modifier = Modifier.height(5.dp)) // Space between Text and Image
+                if (imageState is AsyncImagePainter.State.Success) {
+                    Image(
+                        painter = imageState.painter,
+                        contentDescription = "Описание изображения",
+                        modifier = Modifier
+                            .width(380.dp)
+                            .clip(RoundedCornerShape(20.dp)),
+                    )
+                }
+            }
+            Text(
+                text = "Системные требования к игре:",
+                textAlign = TextAlign.Left,
+                fontFamily = ibmplexmono,
+                fontSize = 20.sp,
+                color = Color.Black,
+            )
+            var GameID = game.id
+            val cloudingame = gamecloud.filter { it.game == GameID }
+            val clouddd = cloudingame.map { it.cloud }
+            val clouds = clouddd.mapNotNull { id ->
+                cloud.find { it.id == id }
+            }
+            val pictureforgame = screen.filter{it.game == GameID}
+            var minn = min.find { it.id_game == GameID }
+            var recc = rec.find { it.id_game == GameID }
+            Column(
+                modifier = Modifier.padding(5.dp)
+            ) {
+                if (minn != null) {
+                    Text(
+                        text = "Минимальные системные требования:",
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Операционная система: " + minn.OS,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Процессор: " + minn.processor,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Оперативная память: " + minn.RAM,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Видеокарта: " + minn.graphic_card,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Свободное место на диске: " + minn.free_space,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp)
+            ) {
+                if (recc != null) {
+                    Text(
+                        text = "Рекомендуемые системные требования:",
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Операционная система: " + recc.OS,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Процессор: " + recc.processor,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Оперативная память: " + recc.RAM,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Видеокарта: " + recc.graphic_card,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    Text(
+                        text = "·Свободное место на диске: " + recc.free_space,
+                        fontFamily = ibmplexmono,
+                        fontSize = 10.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp,0.dp,0.dp,0.dp)
+            ) {
+                Text(
+                    text = "Доступность игры:",
+                    textAlign = TextAlign.Left,
+                    fontFamily = ibmplexmono,
+                    fontSize = 20.sp,
+                    color = Color.Black,
+                )
+                Text(
+                    text = "Официальный источник:",
+                    fontFamily = ibmplexmono,
+                    fontSize = 15.sp,
+                    color = Color.Black,
+                    textAlign = TextAlign.Left
+                )
+                LinkText(game.link_oficial)
+                if(game.link_torrent != null)
+                {
+                    Text(
+                        text = "Сторонний источник:",
+                        fontFamily = ibmplexmono,
+                        fontSize = 15.sp,
+                        color = Color.Black,
+                        textAlign = TextAlign.Left
+                    )
+                    LinkText(game.link_torrent)
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp,0.dp,0.dp,0.dp)
+            )
+            {
+                Text(
+                    text = "Наличие игры в облачном гейминге:",
+                    textAlign = TextAlign.Left,
+                    fontFamily = ibmplexmono,
+                    fontSize = 20.sp,
+                    color = Color.Black,
+                )
+                for(cloud in clouds)
+                {
+                    LinkText(cloud.link)
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp,0.dp,0.dp,0.dp)
+            ) {
+                if(game.description != null) {
+                    Text(
+                        text = "Описание игры:",
+                        textAlign = TextAlign.Left,
+                        fontFamily = ibmplexmono,
+                        fontSize = 20.sp,
+                        color = Color.Black,
+                    )
+                    Text(
+                        game.description,
+                        textAlign = TextAlign.Center,
+                        fontFamily = ibmplexmono,
+                        fontSize = 12.sp,
+                        color = Color.Black,
+                    )
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp,0.dp,0.dp,0.dp)
+            ) {
+                Text(
+                    text = "Скриншоты из игры:",
+                    textAlign = TextAlign.Left,
+                    fontFamily = ibmplexmono,
+                    fontSize = 20.sp,
+                    color = Color.Black,
+                )
+                Row(
+                    modifier = Modifier
+                        .background(color = Color(0xFFFDFFFC), shape = RoundedCornerShape(20.dp))
+                        .height(220.dp)
+                        .fillMaxWidth(),
+                    horizontalArrangement = Arrangement.Center,
+                    verticalAlignment = Alignment.CenterVertically
+                ) {
+                    LazyRow(
+                        modifier = Modifier.fillMaxWidth()
+                    ) {
+                        items(pictureforgame) { screenshot ->
+                            Image(
+                                painter = rememberImagePainter(screenshot.picture),
+                                contentDescription = "Описание изображения",
+                                modifier = Modifier
+                                    .width(380.dp)
+                                    .height(200.dp)
+                                    .clip(RoundedCornerShape(20.dp))
+                                    .padding(4.dp)
+                            )
+                        }
+                    }
+                }
+            }
+            Column(
+                modifier = Modifier.padding(5.dp,0.dp,0.dp,0.dp)
+            )
+            {
+                Text(
+                    text = "Трейлер игры:",
+                    textAlign = TextAlign.Left,
+                    fontFamily = ibmplexmono,
+                    fontSize = 20.sp,
+                    color = Color.Black,
+                )
+                Row(
+                    modifier = Modifier
+                        .background(color = Color(0xFFFDFFFC), shape = RoundedCornerShape(20.dp))
+                        .height(220.dp)
+                        .fillMaxWidth(),
+                    horizontalArrangement = Arrangement.Center,
+                    verticalAlignment = Alignment.CenterVertically
+                )
+                {
+                    if (game.video != null) {
+                        VideoPlayerFromUrl(game.video)
+                    }
+                }
+            }
         }
     }
 }
 
+fun extractVideoId(videoUrl: String): String? {
+    val regex = Regex("(?:https?://)?(?:www\\.)?(?:youtube\\.com/watch\\?v=|youtu\\.be/)([a-zA-Z0-9_-]{11})")
+    return regex.find(videoUrl)?.groups?.get(1)?.value
+}
+
 @Composable
-fun GameItem(game: Game)
-{
-    Text(
-        game.name_game
+fun VideoPlayerFromUrl(videoUrl: String) {
+    val videoId = extractVideoId(videoUrl)
+
+    if (videoId != null) {
+        VideoPlayer(videoId)
+    } else {
+        Text("Неверная ссылка на видео")
+    }
+}
+
+@Composable
+fun VideoPlayer(videoId: String) {
+    AndroidView(
+        factory = { context ->
+            WebView(context).apply {
+                webViewClient = WebViewClient()
+                settings.javaScriptEnabled = true // Включаем JavaScript
+            }
+        },
+        update = { webView ->
+            val html = """
+  <html>
+    <body style="margin:0;padding:0;">
+        <div style="padding: 0 5px;">
+            <iframe 
+                width="100%" 
+                height="200" 
+                src="https://www.youtube.com/embed/$videoId" 
+                frameborder="0" 
+                allowfullscreen 
+                style="border-radius: 15px; overflow: hidden;">
+            </iframe>
+        </div>
+    </body>
+</html>
+            """.trimIndent()
+            webView.loadData(html, "text/html", "UTF-8")
+        },
+        modifier = Modifier.fillMaxWidth().height(200.dp)
+    )
+}
+
+@Composable
+fun LinkText(gameLink: String) {
+    val uriHandler = LocalUriHandler.current
+
+    val annotatedString = buildAnnotatedString {
+        pushStyle(androidx.compose.ui.text.SpanStyle(color = Color.Black, textDecoration = TextDecoration.None))
+        append(gameLink)
+        pop()
+    }
+
+    ClickableText(
+        text = annotatedString,
+        onClick = { offset ->
+            uriHandler.openUri(gameLink)
+        },
+        style = androidx.compose.ui.text.TextStyle(
+            fontFamily = ibmplexmono,
+            fontSize = 15.sp,
+            color = Color.Black,
+            textAlign = TextAlign.Left
+        )
     )
 }

+ 141 - 19
OscellaMobile/app/src/main/java/com/example/oscellamobile/screens/MainWindow.kt

@@ -7,7 +7,6 @@ import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.snapping.SnapPosition
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -26,12 +25,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.Card
-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.SideEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -43,10 +39,6 @@ import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RadialGradientShader
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.Shadow
-import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.painterResource
@@ -55,7 +47,7 @@ import androidx.compose.ui.text.font.FontFamily
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import androidx.navigation.NavHost
+import androidx.navigation.NavController
 import androidx.navigation.NavHostController
 import coil.compose.rememberAsyncImagePainter
 import com.example.oscellamobile.domain.utlis.Constant
@@ -70,14 +62,18 @@ import kotlin.math.sin
 import com.example.oscellamobile.R
 import com.example.oscellamobile.models.Company
 import coil.compose.AsyncImagePainter
-import coil.compose.rememberAsyncImagePainter
 import coil.request.ImageRequest
 import coil.size.Size
+import com.example.oscellamobile.domain.utlis.Constant.supabase
 import com.example.oscellamobile.models.Age_rating
 import com.example.oscellamobile.models.Basic_labels
+import com.example.oscellamobile.models.Favorite
 import com.example.oscellamobile.models.Genre
 import com.example.oscellamobile.models.Label
-import org.intellij.lang.annotations.JdkConstants
+import com.example.oscellamobile.models.Users
+import io.github.jan.supabase.gotrue.auth
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 
 val kdamFontFamily = FontFamily(Font(R.font.kdam))
@@ -111,6 +107,8 @@ fun MainWindow(navHost: NavHostController) {
     var basiclabels by remember{ mutableStateOf<List<Basic_labels>>(listOf()) }
     var age by remember{ mutableStateOf<List<Age_rating>>(listOf()) }
     var genres by remember{ mutableStateOf<List<Genre>>(listOf()) }
+    var user by remember{mutableStateOf<List<Users>>(listOf())}
+    var fav by remember { mutableStateOf<List<Favorite>>(listOf()) }
 
     LaunchedEffect(Unit) {
         withContext(Dispatchers.IO) {
@@ -121,6 +119,8 @@ fun MainWindow(navHost: NavHostController) {
                 basiclabels = Constant.supabase.from("Basic_labels").select().decodeList<Basic_labels>()
                 age = Constant.supabase.from("Age_rating").select().decodeList<Age_rating>()
                 genres = Constant.supabase.from("Genre").select().decodeList<Genre>()
+                user = Constant.supabase.from("Users").select().decodeList<Users>()
+                fav = Constant.supabase.from("Favorite").select().decodeList<Favorite>()
                 games.forEach { Game ->
                     Log.d("C", Game.name_game)
                 }
@@ -165,11 +165,36 @@ fun MainWindow(navHost: NavHostController) {
             Spacer(modifier = Modifier.width(13.dp))
             Text(text = "Osccela", fontSize = 40.sp, fontFamily = kdamFontFamily)
             Spacer(modifier = Modifier.width(145.dp))
-            Image(
-                painter = painterResource(id = R.drawable.personall),
-              contentDescription = "Описание изображения",
-                modifier = Modifier.size(90.dp)
-            )
+            Column(
+                verticalArrangement = Arrangement.Center
+            ) {
+                Image(
+                    painter = painterResource(id = R.drawable.personall),
+                    contentDescription = "Описание изображения",
+                    modifier = Modifier.size(90.dp)
+                )
+                val userId = Constant.supabase.auth.currentUserOrNull()?.id
+                val userIdString = userId.toString()
+                LazyColumn{
+                    items(user) { US ->
+                        if(userIdString == US.user){
+                            Row(
+                                horizontalArrangement = Arrangement.Center,
+                                modifier = Modifier.fillMaxWidth().
+                                padding(0.dp,0.dp,7.dp,0.dp)
+                            ) {
+                                Text(
+                                    US.login,
+                                    fontFamily = kdamFontFamily,
+                                    fontSize = 20.sp,
+                                    color = Color.Black,
+                                    textAlign = TextAlign.Center
+                                )
+                            }
+                        }
+                    }
+                }
+            }
         }
         Row(
             modifier = Modifier
@@ -267,7 +292,9 @@ fun MainWindow(navHost: NavHostController) {
                     basic = basiclabels,
                     age = age,
                     genre = genres,
-                    navHost = navHost
+                    navHost = navHost,
+                    user = user,
+                    fav = fav
                 )
             }
         }
@@ -282,7 +309,9 @@ fun MainWindow(navHost: NavHostController) {
         basic: List<Basic_labels>,
         age: List<Age_rating>,
         genre: List<Genre>,
-        navHost: NavHostController
+        navHost: NavHostController,
+        user: List<Users>,
+        fav: List<Favorite>
     ) {
     val imageState = rememberAsyncImagePainter(
         model = ImageRequest.Builder(LocalContext.current).data(game.picture)
@@ -297,6 +326,9 @@ fun MainWindow(navHost: NavHostController) {
         Row {
             Spacer(Modifier.width(10.dp))
             Column {
+                val userId = Constant.supabase.auth.currentUserOrNull()?.id
+                val userIdString = userId.toString()
+
                 val companyId = game.company
                 val companyy = company.find { it.id == companyId }
                 if (companyy != null) {
@@ -385,13 +417,52 @@ fun MainWindow(navHost: NavHostController) {
                     val size = 31.dp
 
                     var isOrange by remember { mutableStateOf(false) }
+                    val userId = Constant.supabase.auth.currentUserOrNull()?.id
+                    val favv = game.favourites
+                    val userIdString = userId.toString()
+                    val userr = user.find { it.user == userIdString }
+                    LaunchedEffect(Unit) {
+                        if (userr != null) {
+                            val result = fav.find { it.id_game == game.id && it.id_user == userr.id }
+                            if (result != null) {
+                                Log.d("MyApp", "Found favorite: ${result.id_game}, ${result.id_user}")
+                                isOrange = true
 
+                            } else {
+                                Log.d("MyApp", "No favorite found for game ID: ${game.id} and user ID: ${userr.id}")
+                                isOrange = false
+                            }
+                        } else {
+                            Log.d("MyApp", "User  not found for user ID: $userIdString")
+                        }
+                    }
                     val buttonColor = if (isOrange) Color(0xFFFF9F1C) else Color.Gray
 
+
                     Canvas(
                         modifier = Modifier
                             .size(30.dp)
-                            .clickable(onClick = { isOrange = !isOrange })
+                            .clickable(onClick = {
+                                isOrange = !isOrange
+                                if (isOrange) {
+                                    if(userr != null) {
+                                        CoroutineScope(Dispatchers.Main).launch {
+                                            addToFavorites(game.id, userr.id, navHost, favv)
+                                        }
+                                    }
+                                } else {
+                                    if (userr != null) {
+                                        CoroutineScope(Dispatchers.Main).launch {
+                                            removeFromFavorites(
+                                                game.id,
+                                                userr.id,
+                                                navHost,
+                                                favv
+                                            )
+                                        }
+                                    }
+                                }
+                            })
                     ) {
                         drawStar(
                             center = center,
@@ -525,3 +596,54 @@ fun DrawScope.drawStar(center: Offset, radius: Float, color: Color) {
     path.close()
     drawPath(path, color)
 }
+
+suspend fun addToFavorites(id_game: Int, id_user: Int, navController: NavController, fav: Int?) {
+    val newFav = Favorite(
+        id_game = id_game,
+        id_user = id_user
+    )
+
+    val newFavouritesCount = fav?.plus(1) ?: 1
+
+        val response = supabase.from("Game").update(
+            {
+                Game::favourites setTo newFavouritesCount
+                set("favourites", newFavouritesCount)
+            }
+        ) {
+            filter {
+                Game::id eq id_game
+            }
+        }
+
+    withContext(Dispatchers.IO) {
+        supabase.from("Favorite").insert(newFav)
+    }
+    navController.navigate("MainWindow")
+}
+
+suspend fun removeFromFavorites(id_game: Int, id_user: Int, navController: NavController, fav: Int?) {
+    withContext(Dispatchers.IO) {
+
+        val newFavouritesCount = fav?.minus(1) ?: 1
+
+        supabase.from("Game").update(
+            {
+                Game::favourites setTo newFavouritesCount
+                set("favourites", newFavouritesCount)
+            }
+        ) {
+            filter {
+                Game::id eq id_game
+            }
+        }
+
+        val response = supabase.from("Favorite").delete {
+            filter {
+                (Favorite::id_game eq id_game)
+                (Favorite::id_user eq id_user)
+            }
+        }
+    }
+    navController.navigate("MainWindow")
+}