How to switch the position of two buttons randomly؟ - kotlin

I want to switch the positions of the buttons when we press the toggle button. Buttons are repositioned randomly. I tried a lot but was not successful. So if anyone knows how but randomly
val btnOne = findViewById<View>(R.id.buttonOne) as Button
val btnTwo = findViewById<View>(R.id.buttonTwo) as Button
val posOneX = btnOne.x
val posOneY = btnOne.y
val posTwoX = btnTwo.x
val posTwoY = btnTwo.y
btnOne.x = posTwoX
btnOne.y = posTwoY
btnTwo.x = posOneX
btnTwo.y = posOneY

Yes, I found the solution
b4.setOnClickListener {
var arswap = arrayListOf<Button>(b1, b2, b3);
var randomPos: Int = 0;
fun swap(b1: Button, b2: Button) {
var tempPosition = Point(b1.x.toInt(), b1.y.toInt())
b1.x = b2.x;
b1.y = b2.y;
b2.x = tempPosition.x.toFloat();
b2.y = tempPosition.y.toFloat();
}
var totalItems: Int = 3; // total number of items
for (i in 0..totalItems/3 ) {
randomPos = ((Math.random() * arswap.size).toInt());
var randomItem = ((Math.random() * ((totalItems / 2) - 1)) + ((totalItems / 2) + 1));
swap(arswap[randomPos], arswap[randomItem.toInt()])
}
}

Related

Jetpack Compose interface is never updated with new api data

I'm making my first app with Kotlin and Jetpack Compose, I’m still studying. The app, It is a meteorological application that takes the data from an API. The MainScreen starts with the data of the city of Madrid by default, and has a searchBar where you can search for any other city. My problem is that when a new city is introduced in the searchbar, this name travels to the backend and makes the calls to the API, the API responds with the new data but these never come back to the interface. The MainScreen is never updated with new data, but I can see the data on my console.
Any help in welcome, thanks in advance
MainScreen
#RequiresApi(Build.VERSION_CODES.O)
#SuppressLint("UnusedMaterialScaffoldPaddingParameter", "SimpleDateFormat")
#Composable
fun MainScreen(
MainViewModel: MainViewModel
) {
val acceso = Accesso_API()
acceso.coger_tiempo_nombre("Madrid")
while (!acceso.datos_adquiridos) {}
Log.println(Log.ASSERT, "Inicio MainScreen", acceso.resultado.toString())
Surface(
color = MaterialTheme.colors.background,
modifier = Modifier
.fillMaxHeight()
.fillMaxSize()
) {
val searchWidgetState by MainViewModel.searchWidgetState
val searchTextState by MainViewModel.searchTextState
Scaffold(
modifier = Modifier
.fillMaxSize(),
topBar = {
MainAppBar(
searchWidgetState = searchWidgetState,
searchTextState = searchTextState,
onTextChange = {
MainViewModel.updateSearchTextState(newValue = it)
},
onCloseClicked = {
MainViewModel.updateSearchWidgetState(newValue = SearchWidgetState.CLOSED)
},
onSearchClicked = {
Log.d("Searched Text", it)
MainViewModel.searchTextState.value
Log.d("searchTextState", searchTextState)
acceso.coger_tiempo_nombre(searchTextState)
},
onSearchTriggered = {
MainViewModel.updateSearchWidgetState(newValue = SearchWidgetState.OPENED)
}
)
}
) {
Column(
modifier = Modifier
.background(Color.White)
.fillMaxWidth()
.padding(20.dp)
.verticalScroll(rememberScrollState())
) {
//TARJETA PRICIPAL
Card(
modifier = Modifier
.fillMaxWidth(),
backgroundColor = GreyCard,
elevation = 0.dp,
shape = RoundedCornerShape(10.dp)
) {
WeatherDisplayDailyCard(acceso.resultado)
}
//DETALLES
Row(
modifier = Modifier
.padding(
top = 5.dp,
bottom = 0.dp
)
.align(Alignment.CenterHorizontally),
horizontalArrangement = Arrangement.SpaceBetween,
) {
DetailsItem(
details = WeatherDetails(
units = "Pressure",
data = "${acceso.resultado.presion.toString()} mb",
R.drawable.pressure,
color = GreyCard
)
)
DetailsItem(
details = WeatherDetails(
units = "Wind",
data = "${acceso.resultado.viento.toString()} km/h",
R.drawable.wind2,
color = GreyCard
)
)
}
Row(
modifier = Modifier
.padding(
top = 0.dp,
bottom = 0.dp
)
.align(Alignment.CenterHorizontally),
horizontalArrangement = Arrangement.SpaceBetween,
) {
DetailsItem(
details = WeatherDetails(
units = "UV Index",
data = acceso.resultado.uv_text.toString(),
R.drawable.rays,
color = GreyCard
)
)
DetailsItem(
details = WeatherDetails(
units = "Humidity",
data = "${acceso.resultado.humedad_relativa.toString()} %",
R.drawable.water,
color = GreyCard
)
)
}
Spacer(modifier = Modifier.height(16.dp))
//12 HORAS
var hour_1 = acceso.resultado.hora_1;
var hour_2 = acceso.resultado.hora_2;
var hour_3 = acceso.resultado.hora_3;
var hour_4 = acceso.resultado.hora_4;
var hour_5 = acceso.resultado.hora_5;
var hour_6 = acceso.resultado.hora_6;
var hour_7 = acceso.resultado.hora_7;
var hour_8 = acceso.resultado.hora_8;
var hour_9 = acceso.resultado.hora_9;
var hour_10 = acceso.resultado.hora_10;
var hour_11 = acceso.resultado.hora_11;
var hour_12 = acceso.resultado.hora_12;
val formatterHour = DateTimeFormatter.ISO_DATE_TIME
val time1: LocalTime? = LocalTime.parse(hour_1, formatterHour)
val time2: LocalTime? = LocalTime.parse(hour_2, formatterHour)
val time3: LocalTime? = LocalTime.parse(hour_3, formatterHour)
val time4: LocalTime? = LocalTime.parse(hour_4, formatterHour)
val time5: LocalTime? = LocalTime.parse(hour_5, formatterHour)
val time6: LocalTime? = LocalTime.parse(hour_6, formatterHour)
val time7: LocalTime? = LocalTime.parse(hour_7, formatterHour)
val time8: LocalTime? = LocalTime.parse(hour_8, formatterHour)
val time9: LocalTime? = LocalTime.parse(hour_9, formatterHour)
val time10: LocalTime? = LocalTime.parse(hour_10, formatterHour)
val time11: LocalTime? = LocalTime.parse(hour_11, formatterHour)
val time12: LocalTime? = LocalTime.parse(hour_12, formatterHour)
HourlyForecastSheet(
hourlyForecast = listOf(
HourlyDetails(
hour = time1.toString(),
icon = acceso.resultado.icono_hora_1,
temperature = acceso.resultado.temperatura_hora_1
),
HourlyDetails(
hour = time2.toString(),
icon = acceso.resultado.icono_hora_2,
temperature = acceso.resultado.temperatura_hora_2
),
HourlyDetails(
hour = time3.toString(),
icon = acceso.resultado.icono_hora_3,
temperature = acceso.resultado.temperatura_hora_3
),
HourlyDetails(
hour = time4.toString(),
icon = acceso.resultado.icono_hora_4,
temperature = acceso.resultado.temperatura_hora_4
),
HourlyDetails(
hour = time5.toString(),
icon = acceso.resultado.icono_hora_5,
temperature = acceso.resultado.temperatura_hora_5
),
HourlyDetails(
hour = time6.toString(),
icon = acceso.resultado.icono_hora_6,
temperature = acceso.resultado.temperatura_hora_6
),
HourlyDetails(
hour = time7.toString(),
icon = acceso.resultado.icono_hora_7,
temperature = acceso.resultado.temperatura_hora_7
),
HourlyDetails(
hour = time8.toString(),
icon = acceso.resultado.icono_hora_8,
temperature = acceso.resultado.temperatura_hora_8
),
HourlyDetails(
hour = time9.toString(),
icon = acceso.resultado.icono_hora_9,
temperature = acceso.resultado.temperatura_hora_9
),
HourlyDetails(
hour = time10.toString(),
icon = acceso.resultado.icono_hora_10,
temperature = acceso.resultado.temperatura_hora_10
),
HourlyDetails(
hour = time11.toString(),
icon = acceso.resultado.icono_hora_11,
temperature = acceso.resultado.temperatura_hora_11
),
HourlyDetails(
hour = time12.toString(),
icon = acceso.resultado.icono_hora_12,
temperature = acceso.resultado.temperatura_hora_12
),
)
)
Spacer(modifier = Modifier.height(8.dp))
//5 DIAS
Column()
{
val date_1 = acceso.resultado.fecha_dia_1
val date_2 = acceso.resultado.fecha_dia_2
val date_3 = acceso.resultado.fecha_dia_3
val date_4 = acceso.resultado.fecha_dia_4
val date_5 = acceso.resultado.fecha_dia_5
val formatterDate = DateTimeFormatter.ISO_DATE_TIME
val day_1: OffsetDateTime = OffsetDateTime.parse(date_1, formatterDate)
val day_2: OffsetDateTime = OffsetDateTime.parse(date_2, formatterDate)
val day_3: OffsetDateTime = OffsetDateTime.parse(date_3, formatterDate)
val day_4: OffsetDateTime = OffsetDateTime.parse(date_4, formatterDate)
val day_5: OffsetDateTime = OffsetDateTime.parse(date_5, formatterDate)
val date1: DayOfWeek? = LocalDate.from(day_1).dayOfWeek
val date2: DayOfWeek? = LocalDate.from(day_2).dayOfWeek
val date3: DayOfWeek? = LocalDate.from(day_3).dayOfWeek
val date4: DayOfWeek? = LocalDate.from(day_4).dayOfWeek
val date5: DayOfWeek? = LocalDate.from(day_5).dayOfWeek
Next5daysForecastItem(
Next5daysForecast(
date_5days = date1.toString(),
icon_5days = acceso.resultado.icono_dia_1,
temperature_min_5days = acceso.resultado.Temp_min_dia_1,
temperature_max_5days = acceso.resultado.Temp_max_dia_1,
icon_frase_5days = acceso.resultado.frase_dia_1,
)
)
Next5daysForecastItem(
Next5daysForecast(
date_5days = date2.toString(),
icon_5days = acceso.resultado.icono_dia_2,
temperature_min_5days = acceso.resultado.Temp_min_dia_2,
temperature_max_5days = acceso.resultado.Temp_max_dia_2,
icon_frase_5days = acceso.resultado.frase_dia_2,
)
)
Next5daysForecastItem(
Next5daysForecast(
date_5days = date3.toString(),
icon_5days = acceso.resultado.icono_dia_3,
temperature_min_5days = acceso.resultado.Temp_min_dia_3,
temperature_max_5days = acceso.resultado.Temp_max_dia_3,
icon_frase_5days = acceso.resultado.frase_dia_3,
)
)
Next5daysForecastItem(
Next5daysForecast(
date_5days = date4.toString(),
icon_5days = acceso.resultado.icono_dia_4,
temperature_min_5days = acceso.resultado.Temp_min_dia_4,
temperature_max_5days = acceso.resultado.Temp_max_dia_4,
icon_frase_5days = acceso.resultado.frase_dia_4,
)
)
Next5daysForecastItem(
Next5daysForecast(
date_5days = date5.toString(),
icon_5days = acceso.resultado.icono_dia_5,
temperature_min_5days = acceso.resultado.Temp_min_dia_5,
temperature_max_5days = acceso.resultado.Temp_max_dia_5,
icon_frase_5days = acceso.resultado.frase_dia_5,
)
)
Log.println(Log.ASSERT, "Final MainScreen", acceso.resultado.toString())
}
}
}
}
}
MainViewModel
#RequiresApi(Build.VERSION_CODES.O)
class MainViewModel : ViewModel() {
private val _searchWidgetState: MutableState<SearchWidgetState> =
mutableStateOf(value = SearchWidgetState.CLOSED)
val searchWidgetState: State<SearchWidgetState> = _searchWidgetState
private val _searchTextState: MutableState<String> =
mutableStateOf(value = "")
val searchTextState: State<String> = _searchTextState
fun updateSearchWidgetState(newValue: SearchWidgetState) {
_searchWidgetState.value = newValue
}
fun updateSearchTextState(newValue: String) {
_searchTextState.value = newValue
}
}
API_Access
class Accesso_API {
val api_key ="87EYQdAb8jlViEELJJ6KsgJGfkcKG6qu"
#RequiresApi(Build.VERSION_CODES.O)
var resultado: Datos_Tiempo = Datos_Tiempo()
var datos_adquiridos: Boolean = false
#RequiresApi(Build.VERSION_CODES.O)
fun coger_tiempo_posicion_gps(longitud: Float, latitud: Float) {
coger_datos("", longitud,latitud,"")
}
#RequiresApi(Build.VERSION_CODES.O)
fun coger_tiempo_nombre(
nombre: String,
) {
coger_datos(nombre, 0.0f,0.0f,"")
}
#RequiresApi(Build.VERSION_CODES.O)
fun coger_tiempo_key(key: String) {
coger_datos("", 0.0f,0.0f,key)
}
#RequiresApi(Build.VERSION_CODES.O)
private fun coger_datos(nombre: String, longitud: Float, latitud: Float, p_key: String) {
datos_adquiridos = false
val quotesApi = RetrofitHelper.getInstance().create(QuotesApi_Tiempo::class.java)
// launching a new coroutine
GlobalScope.launch {
var key = "308526"
var ciudad_texto = "Sevilla"
Log.println(Log.ASSERT, "", "Ciudad entregada:" + nombre)
if (nombre != "") {
Log.println(Log.ASSERT, "", "Ciudad entregada por nombre:" + nombre)
// Coger la respuesta del rest API de la consulta de localidad por nombre
var respuesta = quotesApi.get_localidad_nombre(nombre, apikey = api_key)
Log.println(Log.ASSERT, "respuesta", respuesta.toString())
// Convertir la respuesta al objeto: List<Localidad>
var ciudades = respuesta.body()
key = ciudades?.get(0)?.Key.toString()
ciudad_texto = ciudades?.get(0)?.EnglishName.toString()
Log.println(Log.ASSERT, "", key)
Log.println(Log.ASSERT, "", ciudad_texto)
}
else {
if (p_key == "") {
// Coger la respuesta del rest API de la consulta de localidad por geoposición (longitud y latitud)
var respuesta = quotesApi.get_localidad_geoposition(
q = longitud.toString() + "," + latitud.toString(),
apikey = api_key
)
// Convertir la respuesta al objeto: Localidad
var ciudad = respuesta.body()
key = ciudad?.Key.toString()
ciudad_texto = ciudad?.localizedName.toString()
} else {
key = p_key
}
}
// Coger la respuesta del rest API de la consulta de las condiciones actuales
val respuesta_cond_act = quotesApi.get_condiciones_actuales(localidad = key, apikey = api_key, details = true, metric = true)
// Convertir la respuesta al objeto: List<Condiciones>
val cond_act = respuesta_cond_act.body()
// Coger la respuesta del rest API de la consulta de la previción de 1 dia
val respuesta_prev_1day = quotesApi.get_prevision_1_dia(localidad = key, apikey = api_key, details = true, metric = true)
// Convertir la respuesta al objeto: Previccion
val prev_1day = respuesta_prev_1day.body()
// Coger la respuesta del rest API de la consulta de la previcción de 5 dias
val respuesta_prev_5d = quotesApi.get_prevision_5_dias(localidad = key, apikey = api_key, details = true, metric = true)
// Convertir la respuesta al objeto: Previccion_5dias
val prev_5d = respuesta_prev_5d.body()
// Coger la respuesta del rest API de la consulta de la previcción de 12 horas
val respuesta_prev_12h = quotesApi.get_prevision_12_horas(localidad = key, apikey = api_key, details = true, metric = true)
// Convertir la respuesta al objeto: List<Previccion_12Horas>
val prev_12h = respuesta_prev_12h.body()
resultado.ciudad = ciudad_texto
// CARTA PRICIPAL
if (cond_act?.get(0) != null) {
resultado.temperatura_actual = cond_act?.get(0)?.Temperature?.Metric?.Value
resultado.unidades_temperatura = cond_act?.get(0)?.Temperature?.Metric?.UnitType.toString()
resultado.icono = cond_act?.get(0)?.WeatherIcon
resultado.icono_frase = cond_act?.get(0)?.WeatherText
}
if (prev_1day != null) {
resultado.temperatura_maxima = prev_1day?.DailyForecasts?.get(0)?.Temperature?.Maximum?.Value
resultado.temperatura_minima = prev_1day?.DailyForecasts?.get(0)?.Temperature?.Minimum?.Value
}
// DETALLES
if (cond_act?.get(0) != null) {
resultado.presion = cond_act?.get(0)?.Pressure?.Metric?.Value
resultado.uv = cond_act?.get(0)?.UVIndex
resultado.uv_text = cond_act?.get(0)?.UVIndexText
resultado.humedad_relativa = cond_act?.get(0)?.RelativeHumidity
resultado.viento = cond_act?.get(0)?.Wind?.Speed?.Metric?.Value
resultado.direccion_viento = cond_act?.get(0)?.Wind?.Direction?.Localized
}
// 12 HORAS
if (prev_12h?.get(0) != null) {
resultado.hora_1 = prev_12h?.get(0)?.DateTime?.toString().toString()
resultado.temperatura_hora_1 = prev_12h?.get(0)?.Temperature?.Value!!
resultado.icono_hora_1 = prev_12h.get(0).WeatherIcon!!
resultado.hora_2 = prev_12h.get(1).DateTime.toString()
resultado.temperatura_hora_2 = prev_12h.get(1).Temperature?.Value!!
resultado.icono_hora_2 = prev_12h.get(1).WeatherIcon!!
resultado.hora_3 = prev_12h.get(2).DateTime.toString()
resultado.temperatura_hora_3 = prev_12h.get(2).Temperature?.Value!!
resultado.icono_hora_3 = prev_12h.get(2).WeatherIcon!!
resultado.hora_4 = prev_12h?.get(3)?.DateTime.toString()
resultado.temperatura_hora_4 = prev_12h.get(3).Temperature?.Value!!
resultado.icono_hora_4 = prev_12h.get(3).WeatherIcon!!
resultado.hora_5 = prev_12h.get(4).DateTime.toString()
resultado.temperatura_hora_5 = prev_12h?.get(4)?.Temperature?.Value!!
resultado.icono_hora_5 = prev_12h?.get(4)?.WeatherIcon!!
resultado.hora_6 = prev_12h?.get(5)?.DateTime.toString()
resultado.temperatura_hora_6 = prev_12h?.get(5)?.Temperature?.Value!!
resultado.icono_hora_6 = prev_12h?.get(5)?.WeatherIcon!!
resultado.hora_7 = prev_12h?.get(6)?.DateTime.toString()
resultado.temperatura_hora_7 = prev_12h?.get(6)?.Temperature?.Value!!
resultado.icono_hora_7 = prev_12h?.get(6)?.WeatherIcon!!
resultado.hora_8 = prev_12h?.get(7)?.DateTime.toString()
resultado.temperatura_hora_8 = prev_12h?.get(7)?.Temperature?.Value!!
resultado.icono_hora_8 = prev_12h?.get(7)?.WeatherIcon!!
resultado.hora_9 = prev_12h?.get(8)?.DateTime.toString()
resultado.temperatura_hora_9 = prev_12h?.get(8)?.Temperature?.Value!!
resultado.icono_hora_9 = prev_12h?.get(8)?.WeatherIcon!!
resultado.hora_10 = prev_12h?.get(9)?.DateTime.toString()
resultado.temperatura_hora_10 = prev_12h?.get(9)?.Temperature?.Value!!
resultado.icono_hora_10 = prev_12h?.get(9)?.WeatherIcon!!
resultado.hora_11 = prev_12h?.get(10)?.DateTime.toString()
resultado.temperatura_hora_11 = prev_12h?.get(10)?.Temperature?.Value!!
resultado.icono_hora_11 = prev_12h?.get(10)?.WeatherIcon!!
resultado.hora_12 = prev_12h?.get(11)?.DateTime.toString()
resultado.temperatura_hora_12 = prev_12h?.get(11)?.Temperature?.Value!!
resultado.icono_hora_12 = prev_12h?.get(11)?.WeatherIcon!!
}
// 5 dias
if (prev_5d != null) {
resultado.fecha_dia_1 = prev_5d?.DailyForecasts?.get(0)?.Date.toString()
resultado.frase_dia_1 = prev_5d?.DailyForecasts?.get(0)?.Day?.ShortPhrase.toString()
resultado.icono_dia_1 = prev_5d?.DailyForecasts?.get(0)?.Day?.Icon!!
resultado.Temp_max_dia_1 = prev_5d?.DailyForecasts?.get(0)?.Temperature?.Maximum?.Value!!
resultado.Temp_min_dia_1 = prev_5d?.DailyForecasts?.get(0)?.Temperature?.Minimum?.Value!!
resultado.fecha_dia_2 = prev_5d?.DailyForecasts?.get(1)?.Date.toString()
resultado.frase_dia_2 = prev_5d?.DailyForecasts?.get(1)?.Day?.ShortPhrase.toString()
resultado.icono_dia_2 = prev_5d?.DailyForecasts?.get(1)?.Day?.Icon!!
resultado.Temp_max_dia_2 = prev_5d?.DailyForecasts?.get(1)?.Temperature?.Maximum?.Value!!
resultado.Temp_min_dia_2 = prev_5d?.DailyForecasts?.get(1)?.Temperature?.Minimum?.Value!!
resultado.fecha_dia_3 = prev_5d?.DailyForecasts?.get(2)?.Date.toString()
resultado.frase_dia_3 = prev_5d?.DailyForecasts?.get(2)?.Day?.ShortPhrase.toString()
resultado.icono_dia_3 = prev_5d?.DailyForecasts?.get(2)?.Day?.Icon!!
resultado.Temp_max_dia_3 =prev_5d?.DailyForecasts?.get(2)?.Temperature?.Maximum?.Value!!
resultado.Temp_min_dia_3 = prev_5d?.DailyForecasts?.get(2)?.Temperature?.Minimum?.Value!!
resultado.fecha_dia_4 = prev_5d?.DailyForecasts?.get(3)?.Date.toString()
resultado.frase_dia_4 = prev_5d?.DailyForecasts?.get(3)?.Day?.ShortPhrase.toString()
resultado.icono_dia_4 = prev_5d?.DailyForecasts?.get(3)?.Day?.Icon!!
resultado.Temp_max_dia_4 = prev_5d?.DailyForecasts?.get(3)?.Temperature?.Maximum?.Value!!
resultado.Temp_min_dia_4 = prev_5d?.DailyForecasts?.get(3)?.Temperature?.Minimum?.Value!!
resultado.fecha_dia_5 = prev_5d?.DailyForecasts?.get(4)?.Date.toString()
resultado.frase_dia_5 = prev_5d?.DailyForecasts?.get(4)?.Day?.ShortPhrase.toString()
resultado.icono_dia_5 = prev_5d?.DailyForecasts?.get(4)?.Day?.Icon!!
resultado.Temp_max_dia_5 = prev_5d?.DailyForecasts?.get(4)?.Temperature?.Maximum?.Value!!
resultado.Temp_min_dia_5 = prev_5d?.DailyForecasts?.get(4)?.Temperature?.Minimum?.Value!!
}
datos_adquiridos = true
Log.println(Log.ASSERT, "datos_tiempo", resultado.toString())
}
}
}
DataModel
data class Datos_Tiempo #RequiresApi(Build.VERSION_CODES.O) constructor(
// Card principal
var ciudad: String? = "Cordoba",
var temperatura_actual: Double? = 18.0,
var temperatura_maxima: Double? = 12.0,
var temperatura_minima: Double? = 6.0,
var unidades_temperatura: String? = "grados",
var icono: Int? = 1,
var icono_frase: String? = "Cloudy",
// Detalles
var presion: Double? = 1020.0,
var direccion_viento: String? = "Sur",
var viento: Double? = 30.0,
var uv: Int? = 4,
var uv_text: String? = "Low",
var humedad_relativa: Double? = 50.0,
#DrawableRes val icon: Int? = R.drawable.ic_1,
val data: String? = "45",
val units: String? = "km/h",
val color: Color? = GreyCard,
//12horas
var hora_1: String = "2022-12-07T12:00:00+01:00",
var icono_hora_1: Int = 6,
var temperatura_hora_1: Double = 13.5,
var temperatura_hora_2: Double = 12.3,
var hora_2: String = "2022-12-07T13:00:00+01:00",
var icono_hora_2: Int = 12,
var temperatura_hora_3: Double = 14.3,
var hora_3: String = "2022-12-07T14:00:00+01:00",
var icono_hora_3: Int = 13,
var temperatura_hora_4: Double = 15.3,
var hora_4: String = "2022-12-07T15:00:00+01:00",
var icono_hora_4: Int = 15,
var temperatura_hora_5: Double = 13.3,
var hora_5: String = "2022-12-07T16:00:00+01:00",
var icono_hora_5: Int = 13,
var temperatura_hora_6: Double = 12.3,
var hora_6: String = "2022-12-07T17:00:00+01:00",
var icono_hora_6: Int = 12,
var temperatura_hora_7: Double = 12.3,
var hora_7: String = "2022-12-07T18:00:00+01:00",
var icono_hora_7: Int = 6,
var temperatura_hora_8: Double = 13.3,
var hora_8: String = "2022-12-07T19:00:00+01:00",
var icono_hora_8: Int = 7,
var temperatura_hora_9: Double = 11.3,
var hora_9: String = "2022-12-07T20:00:00+01:00",
var icono_hora_9: Int = 6,
var temperatura_hora_10: Double = 14.3,
var hora_10: String = "2022-12-07T21:00:00+01:00",
var icono_hora_10: Int = 6,
var temperatura_hora_11: Double = 13.3,
var hora_11: String = "2022-12-07T22:00:00+01:00",
var icono_hora_11: Int = 26,
var temperatura_hora_12: Double = 12.3,
var hora_12: String = "2022-12-07T23:00:00+01:00",
var icono_hora_12: Int = 36,
//5dias
var fecha_dia_1: String = "2022-12-07T18:00:00+01:00",
var frase_dia_1: String = "Mostly Cloudy w/ T-Storms",
var icono_dia_1: Int = 17,
var Temp_max_dia_1: Double = 12.0,
var Temp_min_dia_1: Double = 2.0,
var fecha_dia_2: String = "2022-12-08T18:00:00+01:00",
var frase_dia_2: String = "Rain",
var icono_dia_2: Int = 18,
var Temp_max_dia_2: Double = 15.0,
var Temp_min_dia_2: Double = 4.0,
var fecha_dia_3: String = "2022-12-09T18:00:00+01:00",
var frase_dia_3: String = "Flurries",
var icono_dia_3: Int = 19,
var Temp_max_dia_3: Double = 16.0,
var Temp_min_dia_3: Double = 5.0,
var fecha_dia_4: String = "2022-12-10T18:00:00+01:00",
var frase_dia_4: String = "Mostly Cloudy w/ Flurries",
var icono_dia_4: Int = 20,
var Temp_max_dia_4: Double = 14.0,
var Temp_min_dia_4: Double = 4.0,
var fecha_dia_5: String = "2022-12-11T18:00:00+01:00",
var frase_dia_5: String = "Mostly Cloudy w/ T-Storms",
var icono_dia_5: Int = 16,
var Temp_max_dia_5: Double = 16.0,
var Temp_min_dia_5: Double = 5.0,
)
Two major problems.
First, you are creating your instance of Accesso_API in the Composable, so it is recreated every time things recompose, so you end up with many copies (probably an infinite loop that will eventually crash the device with out-of-memory error), and you are always looking at a new copy who doesn't have any fetched data yet. You need to wrap it in remember { } so it is initialized only once:
val acceso = remember {
Accesso_API()
.apply { coger_tiempo_nombre("Madrid") }
}
Second, you cannot do this kind of thing in UI code:
while (!acceso.datos_adquiridos) {}
This will freeze the whole device because it blocks the main thread.
Compose is meant to be reactive. Don't wait and repeatedly poll values. Create your data property as State that the Composable uses. When the data isn't ready yet, your composable should show a loading indicator or blank screen or something.
So, in your Accesso_API class, change resultado to be MutableState, and you can use null to represent the state when no data is acquired yet:
var resultado: Datos_Tiempo? by mutableStateOf(null)
And completely delete the datos_adquiridos property and any code where you use it.
In your composable, you can get a reference to this state, and you can determine whether it is received yet by checking if it is null.
val resultado = acceso.resultado
if (resultado == null) {
// show screen with loading indicator
return
}
// the rest of your code that builds the screen using non-null resultado.
There could be other problems to fix, but you have so much code I didn't go through it all in detail.
Side note, this kind of repetitive code should be avoided:
//12horas
var hora_1: String = "2022-12-07T12:00:00+01:00",
var icono_hora_1: Int = 6,
var temperatura_hora_1: Double = 13.5,
var temperatura_hora_2: Double = 12.3,
var hora_2: String = "2022-12-07T13:00:00+01:00",
var icono_hora_2: Int = 12,
//...
Use lists or arrays instead of many similar properties! Then you can iterate things and won't have super long functions with repetitive code wherever you work with this data class.

How can i make this animation stop after completion in Jetpack Compose or not be infinite

#Composable
fun Gojo(
maxWidth:Dp,
maxHeight:Dp,)
{
val resource: Painter
val modifier: Modifier
val gojoSize = 200.dp
val infiniteTransition = rememberInfiniteTransition()
val posistionState = infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = LinearEasing
),
repeatMode=RepeatMode.Reverse
)
)
if(posistionState.value<=0.1f) {
modifier = Modifier.offset(
x = -140.dp,
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else if(posistionState.value<=0.2f){
modifier = Modifier.offset(
x = -100.dp,
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else if(posistionState.value<=0.25f){
modifier = Modifier.offset(
x = -100.dp,
y = maxHeight * 0.75f,
).rotate(0.0F)
}
else if(posistionState.value<=0.3f){
modifier = Modifier.offset(
x = -100.dp+(maxWidth*posistionState.value),
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else{
modifier = Modifier.offset(
x = maxWidth * 0.25f,
y = maxHeight * 0.75f,
)
}
resource=painterResource(R.drawable.gojo)
Image(modifier=modifier.width(gojoSize).height(gojoSize),painter = resource, contentDescription ="gojo sama")
}
you are asking for not to be infinite and using infinite transition? just use animateDpAsState and change size of the image by using the dp values. If you want to start the transition when the item has composed just call a LaunchedEffect (true) {startTransition = true} by remembering the startTransition value as false in the beginning:
var startTransition by remember {
mutableStateOf(false)
}
LaunchedEffect(true){
startTransition = true
}
val size = animateDpAsState(
targetValue = if(startTransition == false)
0.dp
else
/*Your Desired Value*/
)
// And use size in Image. You can create different animateDpAsState values for width and height.

displaying alert dialog in the correct location within a recyclerview

I'm making a custom button that when you long press on it a dialog will appear with a list of options to choose from.
The custom button works as it should, however, I'm having some trouble wrangling the dialog to show up exactly where I want it to.
this is the code that displays the dialog.
private void ShowReactionsDialog()
{
var context = Context;
var inflater = (LayoutInflater) context.GetSystemService(Context.LayoutInflaterService);
var dialogView = inflater.Inflate(Resource.Layout.react_dialog_layout, null);
var linearLayoutManager = new LinearLayoutManager(context)
{
Orientation = LinearLayoutManager.Horizontal
};
var adapter = new ReactionAdapter(_reactionList);
adapter.OnItemClicked += (sender, currentReaction) =>
{
UpdateReactButtonByReaction(currentReaction);
_reactAlertDialog.Cancel();
};
var rvReactions = dialogView.FindViewById<RecyclerView>(Resource.Id.reaction_rvReactions);
rvReactions.HasFixedSize = true;
rvReactions.SetLayoutManager(linearLayoutManager);
rvReactions.SetItemAnimator(new DefaultItemAnimator());
rvReactions.SetAdapter(adapter);
var dialogBuilder = new AlertDialog.Builder(context);
dialogBuilder.SetView(dialogView);
_reactAlertDialog = dialogBuilder.Create();
_reactAlertDialog.RequestWindowFeature((int)WindowFeatures.NoTitle);
var window = _reactAlertDialog.Window;
window.SetBackgroundDrawableResource(Resource.Drawable.react_dialog_shape);
window.SetDimAmount(0);
// Setup dialog gravity and dynamic position
var windowManagerAttributes = window.Attributes;
windowManagerAttributes.Gravity = GravityFlags.AxisSpecified;
windowManagerAttributes.X = (int) GetX() + (Width / 2);
windowManagerAttributes.Y = (int) GetY() + (Height / 2);
_reactAlertDialog.Show();
var dialogWidth = GetIconSize() * _reactionList.Count;
if (dialogWidth > GetScreenMaxWidth())
{
dialogWidth = GetScreenMaxWidth();
}
window.SetLayout(dialogWidth, ViewGroup.LayoutParams.WrapContent);
}
I've tried messing with the gravity and the X & Y coordinates but it just wants to either go too high up or too low down, there's no consistent location it's sticking to. I want it to be above the button that's getting long tapped.
You can use the following code to make the AlertDialog show above the button.
int[] location = new int[2];
AndroidX.AppCompat.App.AlertDialog alertDialog = builder.Create();
Window window = alertDialog.Window;
WindowManagerLayoutParams attributes = window.Attributes;
//Get the location of the button and location[0] is X and location[1] is Y
button.GetLocationInWindow(location);
//Set the height of the AlertDialog
int height = 400;
int a = button.Height / 2;
int c = location[1];
//Get the distance of top
attributes.Y = c - a - height;
window.Attributes = attributes;
//Set the AlertDialog location according to the distance of top
window.SetGravity(GravityFlags.Top);
alertDialog.Show();
//Set the Width and Hight of the AlertDialog
alertDialog.Window.SetLayout(800, height);

Contact Test Bit Mask not working proper

contactTestBitMask works in general but if the graphic is too complex contactTestBitMask freaks out and you have only a small contact area or get weird errors. What can i do there?
This is an image about my area:
class GameScene: SKScene, SKPhysicsContactDelegate {
let WallCategory : UInt32 = 0x1 << 1
let ShipCategory : UInt32 = 0x1 << 2
var counter = 0
var userCanBuild1Building = false
var KameraSichtVar:SKCameraNode = SKCameraNode()
var touched:Bool = false
var startTouch = CGPointMake(0, 0)
//------------------------------
var draufgeklickt:CGPoint = CGPoint()
var draufgeklicktUpdate:CGPoint = CGPoint()
var userWantScroll = false
var userWantBuild = false
let wohnhausBlue = SKSpriteNode(imageNamed:"wohnhausBlue")
let buildMenu = SKSpriteNode(imageNamed:"Buildmenu")
var hitDetected = false
let actualBuilding = SKSpriteNode()
var userWantUpgrade : Bool = false
//var theBuildingBefore = SKSpriteNode()
//var houseLvlSave : Int = 0
var uphausSave : String = ""
func didBeginContact(contact: SKPhysicsContact) {
var BuildingObject: SKPhysicsBody
var ClickObject: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask
{
BuildingObject = contact.bodyA
ClickObject = contact.bodyB
}
else
{
BuildingObject = contact.bodyB
ClickObject = contact.bodyA
}
// upgrade Building
let name = BuildingObject.node!.name
let HouseLvL: Int = Int(name!)!
if HouseLvL > 0 && userCanBuild1Building == true{
userCanBuild1Building = false
let touchedBuilding = SKSpriteNode(imageNamed: BuildingObject.node!.name!)
touchedBuilding.name = BuildingObject.node!.name
let name = BuildingObject.node!.name
var HouseLvL: Int = Int(name!)!
HouseLvL = HouseLvL + 1
let uphaus = String(HouseLvL)
let setSpriteTexture = SKAction.setTexture(SKTexture(imageNamed: uphaus))
let upSize = SKSpriteNode(imageNamed: uphaus)
let resizeHousewidth = SKAction.resizeToWidth(upSize.size.width, duration: 0)
let resizeHouseheight = SKAction.resizeToHeight(upSize.size.height, duration: 0)
touchedBuilding.runAction(resizeHousewidth)
touchedBuilding.runAction(resizeHouseheight)
touchedBuilding.runAction(setSpriteTexture)
touchedBuilding.name = "\(uphaus)"
touchedBuilding.position = BuildingObject.node!.position
touchedBuilding.zPosition = BuildingObject.node!.zPosition
touchedBuilding.userInteractionEnabled = false
let upgradedbuilding = SKSpriteNode(imageNamed: uphaus)
touchedBuilding.size = CGSizeMake(upgradedbuilding.size.width, upgradedbuilding.size.height)
touchedBuilding.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed:"\(uphaus)"), size: upgradedbuilding.size)
touchedBuilding.physicsBody?.categoryBitMask = WallCategory
touchedBuilding.physicsBody?.affectedByGravity = false
touchedBuilding.physicsBody?.dynamic = true
touchedBuilding.physicsBody?.collisionBitMask = 0
addChild(touchedBuilding)
BuildingObject.node?.removeFromParent()
ClickObject.node?.removeFromParent()
}
if HouseLvL == 0
{
ClickObject.node?.removeFromParent()
}
}`override func didMoveToView(view: SKView) {
/* Setup your scene here */
if let KameraSicht:SKCameraNode = self.childNodeWithName("Kamera") as? SKCameraNode{
KameraSichtVar = KameraSicht
self.camera = KameraSichtVar
}
physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVectorMake(0, 0)
func addBG(){
let background = SKSpriteNode(imageNamed: "0")
background.name = "0"
background.anchorPoint = CGPointMake(0.5, 0.5)
background.zPosition = 2
background.position = CGPointMake(CGRectGetMinX(self.frame)+self.frame.width/4, CGRectGetMaxY(self.frame)-self.frame.height/4)
background.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "0"), size: background.size)
//background.physicsBody = SKPhysicsBody(rectangleOfSize: background.size)
background.physicsBody?.categoryBitMask = WallCategory
background.physicsBody?.affectedByGravity = false
background.physicsBody?.dynamic = true
background.physicsBody?.collisionBitMask = 0
self.addChild(background)
}
addBG()
let wall = SKSpriteNode(imageNamed:"1" )
wall.name = "1"
wall.zPosition = 10
//wall.xScale = 3
//wall.yScale = 3
wall.size = CGSizeMake(100, 100)
wall.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
wall.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: wall.name!), size: wall.size)
//wall.physicsBody = SKPhysicsBody(rectangleOfSize: wall.size)
wall.physicsBody?.affectedByGravity = false
wall.physicsBody?.dynamic = false
wall.physicsBody!.categoryBitMask = WallCategory
wall.physicsBody?.collisionBitMask = 0
self.addChild(wall)
}
`
ok i found the solution. the problem was the weird behavior of the contactTestBitMask when you use this graphic.(it only detected a contact in a small area of the graphic). the reason for that is that the graphic have separated shapes (like the half ring and some other small stuff).
i connected all shape so that its only one shape and now everything works perfectly fine. also tried it with some other graphics and the behavior of contactTestBitMask is: if you have separated shapes in your graphic, contactTestBitMask take exactly one of the shapes and make it the contact area ...but the other shapes in your graphic will not detect a contact then...

Zedgraph creating too small image

The output of my graph is really small, I can't really see the values at the x and y axis. Is there a way to change this, so the graph is bigger?
My code to output the graph is:
ZedGraphControl zc = new ZedGraphControl();
GraphPane pane = zc.GraphPane;
PointPairList list1 = new PointPairList();
LineItem curve1;
pane.Title.Text = title;
pane.XAxis.Title.Text = xAxisTitle;
pane.XAxis.Scale.Min = 0;
pane.XAxis.Scale.Max = 11;
pane.YAxis.Scale.Min = 1;
pane.YAxis.Scale.Max = 12;
pane.YAxis.Title.Text = yAXisTitle;
Int32 totalCount = ds.Tables[objectName].Rows.Count;
double[] xVals = new double[totalCount], yVals = new double[totalCount];
for (int i = 0; i < totalCount; i++)
{
xVals[i] = Convert.ToDouble(ds.Tables[objectName].Rows[i]["ntotal"]);
yVals[i] = Convert.ToDouble(ds.Tables[objectName].Rows[i]["isomonth"]);
}
list1.Add(xVals, yVals);
curve1 = pane.AddCurve("Temp curve", list1, Color.Green, SymbolType.Circle);
for (int i = 0; i < totalCount; i++)
{
TextObj t = new TextObj("Teest", curve1.Points[i].Y, curve1.Points[i].X);
t.FontSpec.Border.IsVisible = false;
pane.GraphObjList.Add(t);
}
curve1.Line.Width = 1.0F;
pane.GetImage().Save(outPutDestination, ImageFormat.Png);
pane.AxisChange();
GetImage() function gets the current size of the pane, so we just have to increase the size of the entire pane(i.e: dock & maximize the window & then use the method to get the image).
DockStyle currentStyle = zedGraphControl1.Dock;
var currentWindowState = this.WindowState;
zedGraphControl1.Dock = DockStyle.Fill;
this.WindowState = FormWindowState.Maximized;
zedGraphControl1.GetImage ().Save ( #"c:\Image_1.png" );
this.WindowState = currentWindowState;
zedGraphControl1.Dock = currentStyle;