Advertisement
thevals

mobdevlr3

May 24th, 2024 (edited)
836
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 15.08 KB | None | 0 0
  1. //#################################
  2. //MainActivity.kt
  3. //#################################
  4.  
  5. package com.thevals.lab3
  6.  
  7. import android.os.Bundle
  8. import androidx.activity.ComponentActivity
  9. import androidx.activity.compose.setContent
  10. import androidx.compose.foundation.layout.Arrangement
  11. import androidx.compose.foundation.layout.fillMaxSize
  12. import androidx.compose.material3.MaterialTheme
  13. import androidx.compose.material3.Surface
  14. import androidx.compose.material3.Text
  15. import androidx.compose.material3.Button
  16. import androidx.compose.foundation.layout.Column
  17. //import androidx.compose.foundation.layout.Spacer
  18. import androidx.compose.runtime.Composable
  19. import androidx.compose.ui.Alignment
  20. import androidx.compose.ui.Modifier
  21. import androidx.compose.ui.tooling.preview.Preview
  22. import androidx.navigation.NavController
  23. import androidx.navigation.compose.rememberNavController
  24. import androidx.navigation.compose.NavHost
  25. import androidx.navigation.compose.composable
  26.  
  27. import com.thevals.lab3.ui.theme.Lab3Theme
  28.  
  29. class MainActivity : ComponentActivity() {
  30.     override fun onCreate(savedInstanceState: Bundle?) {
  31.         super.onCreate(savedInstanceState)
  32.         setContent {
  33.             Lab3Theme {
  34.                 // A surface container using the 'background' color from the theme
  35.                 Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
  36.                     App()
  37.                 }
  38.             }
  39.         }
  40.     }
  41. }
  42.  
  43. @Composable
  44. fun App(){
  45.     val appNavController = rememberNavController()
  46.     NavHost(navController = appNavController, startDestination = "main"){
  47.         composable("main") { MainScreen(navController = appNavController)}
  48.         composable("t1") { T1Screen(navController = appNavController)}
  49.         composable("t2") { T2Screen(navController = appNavController)}
  50.         composable("t3") { T3Screen(navController = appNavController)}
  51.     }
  52. }
  53.  
  54.  
  55. @Composable
  56. fun MainScreen(navController:NavController){
  57.     Column(
  58.         modifier = Modifier.fillMaxSize(),
  59.         verticalArrangement = Arrangement.Center,
  60.         horizontalAlignment = Alignment.CenterHorizontally
  61.     ) {
  62.         Button(onClick = { navController.navigate("t1") }) {
  63.             Text("T1: ФИО")
  64.         }
  65.         Button(onClick = { navController.navigate("t2") }) {
  66.             Text("T2: REST API")
  67.         }
  68.         Button(onClick = { navController.navigate("t3") }) {
  69.             Text("T3: БД")
  70.         }
  71.     }
  72. }
  73.  
  74. @Composable
  75. @Preview
  76. fun PreviewApp(){
  77.     App()
  78. }
  79.  
  80.  
  81. //#################################
  82. //T1Screen.kt
  83. //#################################
  84.  
  85.  
  86. package com.thevals.lab3
  87.  
  88. import androidx.compose.foundation.layout.Arrangement
  89. import androidx.compose.foundation.layout.Column
  90. import androidx.compose.foundation.layout.fillMaxSize
  91. import androidx.compose.material3.Button
  92. import androidx.compose.material3.Text
  93. import androidx.compose.runtime.Composable
  94. import androidx.compose.ui.Alignment
  95. import androidx.compose.ui.Modifier
  96. import androidx.navigation.NavController
  97.  
  98. @Composable
  99. fun T1Screen(navController: NavController){
  100.     Column(
  101.         modifier = Modifier.fillMaxSize(),
  102.         verticalArrangement = Arrangement.Center,
  103.         horizontalAlignment = Alignment.CenterHorizontally
  104.     ) {
  105.         Text("Волков Сергей Алексеевич")
  106.         Button(onClick = {navController.navigate("main")}){
  107.             Text("Back")
  108.         }
  109.     }
  110. }
  111.  
  112.  
  113.  
  114. //#################################
  115. //T2Screen.kt
  116. //#################################
  117.  
  118.  
  119.  
  120. package com.thevals.lab3
  121.  
  122. import androidx.compose.foundation.layout.Column
  123. import androidx.compose.foundation.layout.fillMaxSize
  124. import androidx.compose.foundation.layout.Arrangement
  125. import androidx.compose.foundation.layout.fillMaxWidth
  126. import androidx.compose.foundation.layout.height
  127. import androidx.compose.foundation.layout.width
  128. import androidx.compose.foundation.layout.padding
  129. import androidx.compose.foundation.shape.RoundedCornerShape
  130. import androidx.compose.foundation.Image
  131. import coil.compose.rememberImagePainter
  132. import androidx.compose.ui.unit.dp
  133. import androidx.compose.ui.layout.ContentScale
  134. import androidx.compose.ui.graphics.painter.Painter
  135. import androidx.compose.material3.Button
  136. import androidx.compose.material3.Text
  137. import androidx.compose.runtime.Composable
  138. import androidx.compose.ui.Alignment
  139. import androidx.compose.ui.Modifier
  140. import androidx.compose.material3.Card
  141. import androidx.compose.material3.MaterialTheme
  142. import androidx.navigation.NavController
  143. import androidx.compose.material3.TextField
  144. import androidx.compose.runtime.getValue
  145. import androidx.compose.runtime.setValue
  146. import androidx.compose.runtime.remember
  147. import androidx.compose.runtime.mutableStateOf
  148. import kotlinx.coroutines.Dispatchers
  149. import androidx.compose.runtime.rememberCoroutineScope
  150. import androidx.compose.ui.window.Dialog
  151. import kotlinx.coroutines.launch
  152. import kotlinx.serialization.Serializable
  153. import kotlinx.serialization.decodeFromString
  154. import kotlinx.serialization.json.Json
  155. import kotlinx.coroutines.withContext
  156. import okhttp3.OkHttpClient
  157. import okhttp3.Request
  158.  
  159. //Задаем сериализацию для JSON результата
  160. @Serializable
  161. data class PokemonForm(
  162.     val name: String
  163. )
  164.  
  165. @Serializable
  166. data class PokemonInfo(
  167.     val id: Int,
  168.     val forms: List<PokemonForm>
  169. )
  170.  
  171. @Serializable
  172. data class PokemonFormInfo(
  173.     val id: Int,
  174.     val types: List<PokemonType>,
  175.     val version_group: VersionGroup,
  176.     val sprites: Sprites,
  177.     val name: String
  178. )
  179.  
  180. @Serializable
  181. data class PokemonType(
  182.     val type: Type
  183. )
  184.  
  185. @Serializable
  186. data class Type(
  187.     val name: String
  188. )
  189.  
  190. @Serializable
  191. data class VersionGroup(
  192.     val name: String
  193. )
  194.  
  195. @Serializable
  196. data class Sprites(
  197.     val front_default: String
  198. )
  199.  
  200. //Основная активность в Compose колонне
  201. @Composable
  202. fun T2Screen(navController: NavController) {
  203.     val coroutineScope = rememberCoroutineScope()
  204.     var pokemonInfo by remember { mutableStateOf<PokemonFormInfo?>(null) }
  205.     var showDialog by remember {mutableStateOf(false)}
  206.     var isError by remember {mutableStateOf(false)}
  207.     Column(
  208.         modifier = Modifier.fillMaxSize(),
  209.         verticalArrangement = Arrangement.Center,
  210.         horizontalAlignment = Alignment.CenterHorizontally
  211.     ) {
  212.         var text by remember {mutableStateOf("")}
  213.         Text("REST API")
  214.         TextField(
  215.             value = text,
  216.             onValueChange = { text = it },
  217.             label = { Text("Enter Pokemon name")},
  218.             supportingText = {
  219.                 if(isError){
  220.                     Text("Error! No Pokemon with this name in API", color = MaterialTheme.colorScheme.error)
  221.                 }
  222.             }
  223.         )
  224.         Button(onClick={
  225.             showDialog = true
  226.             isError = false
  227.             if(text != "") {
  228.                 coroutineScope.launch {
  229.                     val pokemonQuery = getPokemonInfo(text)
  230.                     if (pokemonQuery == "") {
  231.                         isError = true
  232.                     } else {
  233.                         pokemonInfo = json.decodeFromString<PokemonFormInfo>(pokemonQuery)
  234.                     }
  235.                 }
  236.             } else isError = true
  237.         }){
  238.             Text("Get info")
  239.         }
  240.         Button(onClick = { navController.navigate("main") }) {
  241.             Text("Back")
  242.         }
  243.     }
  244.     if(showDialog && pokemonInfo != null) {
  245.         val painter = rememberImagePainter(pokemonInfo!!.sprites.front_default)
  246.         var cardText = "ID: " + pokemonInfo!!.id + "\nName: " +
  247.         pokemonInfo!!.name + "\nVersion: " + pokemonInfo!!.version_group.name + "\nTypes: "
  248.         for(type in pokemonInfo!!.types){
  249.             cardText+=type.type.name
  250.             cardText+=","
  251.         }
  252.         cardText = cardText.dropLast(1)
  253.  
  254.         InfoDialog(
  255.             onDismissRequest = {
  256.                 showDialog = false
  257.                 pokemonInfo = null
  258.                                },
  259.             painter = painter,
  260.             imageDescription = "sprite",
  261.             cardText = cardText
  262.         )
  263.     }
  264. }
  265.  
  266. @Composable
  267. fun InfoDialog(
  268.     onDismissRequest: () -> Unit,
  269.     painter: Painter,
  270.     imageDescription: String,
  271.     cardText: String,
  272. ) {
  273.     Dialog(onDismissRequest = { onDismissRequest() }) {
  274.         // Draw a rectangle shape with rounded corners inside the dialog
  275.         Card(
  276.             modifier = Modifier
  277.                 .fillMaxWidth()
  278.                 .height(375.dp)
  279.                 .padding(16.dp),
  280.             shape = RoundedCornerShape(16.dp),
  281.         ) {
  282.             Column(
  283.                 modifier = Modifier
  284.                     .fillMaxSize(),
  285.                 verticalArrangement = Arrangement.Center,
  286.                 horizontalAlignment = Alignment.CenterHorizontally,
  287.             ) {
  288.                 Image(
  289.                     painter = painter,
  290.                     contentDescription = imageDescription,
  291.                     contentScale = ContentScale.FillBounds,
  292.                     modifier = Modifier
  293.                         .height(160.dp)
  294.                         .width(160.dp)
  295.                 )
  296.                 Text(
  297.                     text = cardText,
  298.                     modifier = Modifier.padding(16.dp),
  299.                 )
  300.                     Button(
  301.                         onClick = { onDismissRequest() },
  302.                         modifier = Modifier.padding(8.dp)
  303.                     ){
  304.                         Text("Close")
  305.                     }
  306.             }
  307.         }
  308.     }
  309. }
  310.  
  311. private val json: Json = Json { ignoreUnknownKeys = true }
  312.  
  313. suspend fun getPokemonInfo(pokemonNameInput: String):String{
  314.     //создаём запрос к общей информации о покемоне
  315.     var pokemonName = pokemonNameInput.replaceFirstChar {
  316.         if (it.isUpperCase()) it.lowercase() else it.toString()
  317.     }
  318.     pokemonName = pokemonName.trimEnd()
  319.  
  320.     val url = "https://pokeapi.co/api/v2/pokemon/$pokemonName"
  321.     val request = Request.Builder().url(url).build()
  322.     var formResponseBody = ""
  323.     withContext(Dispatchers.IO) {
  324.         val client = OkHttpClient()
  325.         val response = client.newCall(request).execute()
  326.         var responseBody = response.body?.string() ?: ""
  327.         if(response.code == 404) responseBody = ""
  328.         if(responseBody != "") {
  329.             val pokemonInfo = json.decodeFromString<PokemonInfo>(responseBody)
  330.  
  331.             //из полученной информации делаем запрос с получением подробной информации о первой
  332.             //форме покемона
  333.             val formRequest = Request.Builder()
  334.                 .url("https://pokeapi.co/api/v2/pokemon-form/${pokemonInfo.forms[0].name}").build()
  335.             val formResponse = client.newCall(formRequest).execute()
  336.             formResponseBody = formResponse.body?.string() ?: ""
  337.         }
  338.     }
  339.     return formResponseBody
  340. }
  341.  
  342.  
  343.  
  344.  
  345.  
  346. //#################################
  347. //T3Screen.kt
  348. //#################################
  349.  
  350. package com.thevals.lab3
  351.  
  352. import androidx.compose.foundation.layout.Arrangement
  353. import androidx.compose.foundation.layout.Column
  354. import androidx.compose.foundation.layout.Row
  355. import androidx.compose.foundation.layout.fillMaxSize
  356. import androidx.compose.material3.Button
  357. import androidx.compose.material3.Icon
  358. import androidx.compose.material3.IconButton
  359. import androidx.compose.material3.MaterialTheme
  360. import androidx.compose.material3.Text
  361. import androidx.compose.material3.TextField
  362. import androidx.compose.runtime.remember
  363. import androidx.compose.runtime.LaunchedEffect
  364. import androidx.compose.runtime.rememberCoroutineScope
  365. import androidx.compose.runtime.mutableStateOf
  366. import androidx.compose.ui.Alignment
  367. import androidx.compose.ui.Modifier
  368. import androidx.compose.ui.res.painterResource
  369. import androidx.compose.ui.platform.LocalContext
  370. import androidx.compose.runtime.getValue
  371. import androidx.compose.runtime.setValue
  372. import androidx.compose.runtime.Composable
  373. import androidx.navigation.NavController
  374. import android.widget.Toast
  375. import kotlinx.coroutines.withContext
  376. import okhttp3.OkHttpClient
  377. import okhttp3.Request
  378. import kotlinx.coroutines.launch
  379. import kotlinx.coroutines.Dispatchers
  380. import okhttp3.MediaType.Companion.toMediaType
  381. import okhttp3.RequestBody.Companion.toRequestBody
  382.  
  383. @Composable
  384. fun T3Screen(navController: NavController) {
  385.     val coroutineScope = rememberCoroutineScope()
  386.     var rating by remember { mutableStateOf(0) }
  387.     var isError by remember { mutableStateOf(false) }
  388.     var cnt by remember { mutableStateOf(0) }
  389.     var feedback by remember { mutableStateOf("") }
  390.     val context = LocalContext.current
  391.  
  392.     Column(
  393.         modifier = Modifier.fillMaxSize(),
  394.         verticalArrangement = Arrangement.Center,
  395.         horizontalAlignment = Alignment.CenterHorizontally
  396.     ) {
  397.         Text("Feedback")
  398.         Row {
  399.             for (i in 1..5) {
  400.                 IconButton(onClick = { rating = i }) {
  401.                     Icon(
  402.                         painter = if (i <= rating) painterResource(id = R.drawable.round_star_24) else painterResource(
  403.                             id = R.drawable.round_star_border_24
  404.                         ), contentDescription = null
  405.                     )
  406.                 }
  407.             }
  408.         }
  409.         TextField(
  410.             value = feedback,
  411.             onValueChange = { feedback = it },
  412.             label = { Text("Feedback") },
  413.             supportingText = {
  414.                 if (isError) {
  415.                     Text("API returned error", color = MaterialTheme.colorScheme.error)
  416.                 }
  417.             }
  418.         )
  419.         Button(onClick = {
  420.             coroutineScope.launch {
  421.                 val json = """
  422.                    {
  423.                "title": "$rating",
  424.                "body": "$feedback",
  425.                "userId": $cnt
  426.                    }
  427.                """.trimIndent()
  428.  
  429.                 val client = OkHttpClient()
  430.                 val mediaType = "application/json; charset=utf-8".toMediaType()
  431.                 val requestBody = json.toRequestBody(mediaType)
  432.                 val request = Request.Builder()
  433.                     .url("https://jsonplaceholder.typicode.com/posts")
  434.                     .post(requestBody)
  435.                     .build()
  436.  
  437.                 withContext(Dispatchers.IO) {
  438.                     val response = client.newCall(request).execute()
  439.                     if (response.code == 201 && rating > 0) {
  440.                         cnt++
  441.                         isError = false
  442.                     } else isError = true
  443.                 }
  444.             }
  445.         }) {
  446.             Text("Send")
  447.         }
  448.         Button(onClick = { navController.navigate("main") }) {
  449.             Text("Back")
  450.         }
  451.         if (cnt > 0) LaunchedEffect(key1 = cnt) {
  452.             if (!isError) {
  453.                 Toast.makeText(
  454.                     context,
  455.                     "Feedback sent successfully! Thank you!",
  456.                     Toast.LENGTH_LONG
  457.                 ).show()
  458.             }
  459.         }
  460.  
  461.     }
  462. }
  463.  
  464.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement