Added connection to teachers information api, formatted code, updated gradle

This commit is contained in:
Mariano Riefolo 2024-04-12 22:50:24 +02:00
parent 5d09a7fc7b
commit adaf82d7af
7 changed files with 142 additions and 101 deletions

View File

@ -1,6 +1,7 @@
package it.edu.cassandroferminervi.flowschool.remote package it.edu.cassandroferminervi.flowschool.remote
import it.edu.cassandroferminervi.flowschool.remote.dto.LoginResult import it.edu.cassandroferminervi.flowschool.remote.dto.LoginResult
import it.edu.cassandroferminervi.flowschool.remote.dto.TeacherInfoResult
import retrofit2.Response import retrofit2.Response
import retrofit2.http.Field import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded import retrofit2.http.FormUrlEncoded
@ -9,5 +10,23 @@ import retrofit2.http.POST
interface ApiService { interface ApiService {
@FormUrlEncoded @FormUrlEncoded
@POST("login.php") @POST("login.php")
suspend fun postLogin(@Field("username") code: String, @Field("password") password: String): Response<LoginResult> suspend fun postLogin(
@Field("username") code: String,
@Field("password") password: String
): Response<LoginResult>
@FormUrlEncoded
@POST("presenza.php")
suspend fun postPresence(@Field("token") token: String): Response<Boolean>
@FormUrlEncoded
@POST("lista.php")
suspend fun postTeacherList(@Field("token") token: String): Response<List<TeacherInfoResult>>
@FormUrlEncoded
@POST("ricerca.php")
suspend fun postTeacherInfo(
@Field("token") token: String,
@Field("profId") teacherId: Int
): Response<TeacherInfoResult>
} }

View File

@ -0,0 +1,11 @@
package it.edu.cassandroferminervi.flowschool.remote.dto
import androidx.annotation.Keep
@Keep
data class TeacherInfoResult(
val codice: Int,
val nome: String,
val cognome: String,
val email: String?
)

View File

@ -90,8 +90,8 @@ fun LoginScreen(navigator: DestinationsNavigator) {
val description = if (passwordVisible) "Nascondi password" else "Mostra password" val description = if (passwordVisible) "Nascondi password" else "Mostra password"
IconButton(onClick = {passwordVisible = !passwordVisible}){ IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(imageVector = image, description) Icon(imageVector = image, description)
} }
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()

View File

@ -22,7 +22,7 @@ fun PermissionScreen(token: String) {
if (cameraPermissionState.status.isGranted) { if (cameraPermissionState.status.isGranted) {
CameraScreen() CameraScreen()
} else { } else {
Box ( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {

View File

@ -1,129 +1,104 @@
package it.edu.cassandroferminervi.flowschool.screens package it.edu.cassandroferminervi.flowschool.screens
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.ramcosta.composedestinations.TeacherScreenDestination import com.ramcosta.composedestinations.TeacherScreenDestination
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import it.edu.cassandroferminervi.flowschool.remote.RetrofitInstance
import it.edu.cassandroferminervi.flowschool.remote.dto.TeacherInfoResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalFoundationApi::class)
@Destination @Destination
@Composable @Composable
fun SearchingScreen(navigator: DestinationsNavigator, token: String) { fun SearchingScreen(
val teachers = listOf( navigator: DestinationsNavigator,
"Mario Rossi", token: String,
"Michele Verdi", ) {
"Fabio Bianchi" val context = LocalContext.current
).groupBy {
it.first() var professorList by remember { mutableStateOf<List<TeacherInfoResult>>(emptyList()) }
}.toSortedMap() var searchText by remember { mutableStateOf("") }
.map {
Category( LaunchedEffect(Unit) {
it.key.toString(), val response = withContext(Dispatchers.IO) {
items = it.value RetrofitInstance.api.postTeacherList(token)
)
} }
var filter by remember { mutableStateOf("") } if (response.isSuccessful) {
professorList = response.body() ?: emptyList()
} else {
Toast.makeText(context, "Errore nel server", Toast.LENGTH_SHORT).show()
}
}
val groupedByLetter = professorList.sortedWith(compareBy({ it.cognome }, { it.nome }))
.groupBy { it.cognome.first().uppercaseChar() }
Column { Column {
TextField( OutlinedTextField(
value = filter, value = searchText,
onValueChange = { filter = it }, onValueChange = { searchText = it },
label = { Text("Cerca") }, label = { Text("Cerca professore") },
singleLine = true,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) )
CategorizedLazyColumn( LazyColumn {
categories = teachers, groupedByLetter.forEach { (letter, professors) ->
navigator = navigator,
filter = filter
)
}
}
data class Category(
val name: String,
val items: List<String>
)
@Composable
private fun CategoryHeader(
text: String,
modifier: Modifier = Modifier
) {
Text(
text = text,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(16.dp)
)
}
@Composable
private fun CategoryItem(
text: String,
navigator: DestinationsNavigator,
modifier: Modifier = Modifier
) {
TextButton(onClick = {
navigator.navigate(TeacherScreenDestination("test"))
}) {
Text(
text = text,
fontSize = 14.sp,
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(16.dp)
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun CategorizedLazyColumn(
categories: List<Category>,
navigator: DestinationsNavigator,
filter: String,
modifier: Modifier = Modifier
) {
LazyColumn(modifier) {
categories.forEach { category ->
if (category.items.any {
it.contains(filter, ignoreCase = true)
}) {
stickyHeader { stickyHeader {
CategoryHeader(category.name) Text(
text = letter.toString(),
style = TextStyle(fontWeight = FontWeight.Bold),
modifier = Modifier
.fillMaxWidth()
.background(Color.LightGray)
.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
items(professors.filter {
it.nome.contains(searchText, ignoreCase = true) ||
it.cognome.contains(searchText, ignoreCase = true)
}) { professor ->
ProfessorItem(navigator = navigator, token = token, professor = professor)
} }
}
items(items = category.items.filter {
it.contains(filter, ignoreCase = true)
}) { text ->
CategoryItem(text, navigator)
} }
} }
} }
} }
@Composable
fun ProfessorItem(navigator: DestinationsNavigator, token: String, professor: TeacherInfoResult) {
Column(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = {
navigator.navigate(TeacherScreenDestination(token, professor.codice))
})
.padding(16.dp)
) {
Text(text = "${professor.nome} ${professor.cognome}")
}
}

View File

@ -1,23 +1,59 @@
package it.edu.cassandroferminervi.flowschool.screens package it.edu.cassandroferminervi.flowschool.screens
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import it.edu.cassandroferminervi.flowschool.remote.RetrofitInstance
import it.edu.cassandroferminervi.flowschool.remote.dto.TeacherInfoResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Destination @Destination
@Composable @Composable
fun TeacherScreen(codice: String) { fun TeacherScreen(token: String, code: Int) {
val context = LocalContext.current
var resBody by remember {
mutableStateOf(
TeacherInfoResult(
code,
"err",
"err",
null
)
)
}
LaunchedEffect(Unit) {
val response = withContext(Dispatchers.IO) {
RetrofitInstance.api.postTeacherInfo(token, code)
}
if (response.isSuccessful && response.body() != null) {
resBody = response.body()!!
} else {
Toast.makeText(context, "Errore nel server", Toast.LENGTH_SHORT).show()
}
}
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
Text("Codice prof: $codice") Text("Nome: ${resBody.nome}")
Text("Presente: si") Text("Cognome: ${resBody.cognome}")
Text("Email: ${resBody.email}")
} }
} }

View File

@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.3.1" apply false id("com.android.application") version "8.3.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false id("org.jetbrains.kotlin.android") version "1.9.0" apply false
} }