From 30c7fb1b2a97ac1ca930cea94852747a9698d1e2 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 16 Jun 2024 17:59:22 +0200 Subject: [PATCH 1/7] fixed connection over internet --- .../connectivity/task/TaskClient.kt | 25 +-- .../connectivity/task/TaskServer.kt | 4 +- .../task/api/TaskSessionManagerClientApi.kt | 58 +++++++ ...rApi.kt => TaskSessionManagerServerApi.kt} | 59 ++++--- .../connectivity/task/session/TaskSession.kt | 5 +- .../tasks_valider/database/dao/PersonDao.kt | 6 + .../database/entities/ClassEntity.kt | 5 +- .../database/entities/PersonEntity.kt | 12 +- .../entities/RelationClassPersonEntity.kt | 5 +- .../RelationPersonSessionSubjectEntity.kt | 7 +- .../database/entities/SessionEntity.kt | 7 +- .../database/entities/SubjectEntity.kt | 5 +- .../database/entities/TaskEntity.kt | 11 +- .../database/entities/ValidationEntity.kt | 9 +- .../database/entities/error/HttpException.kt | 6 +- .../ui/screen/authentication/client.kt | 146 ++++++++++++++++++ .../server.kt | 4 +- .../ui/screen/authentification/client.kt | 40 ----- .../screen/communication/internet/client.kt | 54 +++++-- .../screen/communication/internet/server.kt | 5 +- .../ui/screen/communication/selection.kt | 1 - .../ui/screen/task/quick_validation.kt | 10 +- .../tasks_valider/ui/screen/task/session.kt | 17 +- .../tasks_valider/ui/screen/task/student.kt | 10 +- .../com/faraphel/tasks_valider/utils/json.kt | 1 + 25 files changed, 371 insertions(+), 141 deletions(-) create mode 100644 app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerClientApi.kt rename app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/{TaskSessionManagerApi.kt => TaskSessionManagerServerApi.kt} (80%) create mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/{authentification => authentication}/server.kt (93%) delete mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/client.kt diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskClient.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskClient.kt index e4b7bd5..7f48023 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskClient.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskClient.kt @@ -1,5 +1,6 @@ package com.faraphel.tasks_valider.connectivity.task +import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerClientApi import com.faraphel.tasks_valider.database.api.client.TaskEntityHttpClient import com.faraphel.tasks_valider.database.api.client.entities.* @@ -17,13 +18,19 @@ class TaskClient( ) { private val httpClient = TaskEntityHttpClient(address, port, baseCookies) - val clientApi = ClassClientApi(httpClient) - val personApi = PersonClientApi(httpClient) - val sessionApi = SessionClientApi(httpClient) - val subjectApi = SubjectClientApi(httpClient) - val taskApi = TaskClientApi(httpClient) - val validationApi = ValidationClientApi(httpClient) + // all the entities API + class Entities(httpClient: TaskEntityHttpClient) { + val client = ClassClientApi(httpClient) + val person = PersonClientApi(httpClient) + val session = SessionClientApi(httpClient) + val subject = SubjectClientApi(httpClient) + val task = TaskClientApi(httpClient) + val validation = ValidationClientApi(httpClient) - val relationClassPersonApi = RelationClassPersonClientApi(httpClient) - val relationPersonSessionSubjectApi = RelationPersonSessionSubjectClientApi(httpClient) -} \ No newline at end of file + val relationClassPerson = RelationClassPersonClientApi(httpClient) + val relationPersonSessionSubject = RelationPersonSessionSubjectClientApi(httpClient) + } + val entities = Entities(httpClient) + + val session = TaskSessionManagerClientApi(httpClient) +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskServer.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskServer.kt index a4c1893..640aeff 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskServer.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/TaskServer.kt @@ -1,6 +1,6 @@ package com.faraphel.tasks_valider.connectivity.task -import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerApi +import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerServerApi import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager import com.faraphel.tasks_valider.database.TaskDatabase import com.faraphel.tasks_valider.database.api.server.DatabaseApi @@ -24,7 +24,7 @@ class TaskServer( ) : NanoHTTPD(port) { private val sessionManager = TaskSessionManager(adminPersonEntity) ///< the session manager private val databaseApi = DatabaseApi(this.database, session) ///< the api of the database - private val sessionManagerApi = TaskSessionManagerApi(this.sessionManager, this.database) ///< the api of the session manager + private val sessionManagerApi = TaskSessionManagerServerApi(this.sessionManager, this.database) ///< the api of the session manager /** * Get the admin person entity diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerClientApi.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerClientApi.kt new file mode 100644 index 0000000..1267a22 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerClientApi.kt @@ -0,0 +1,58 @@ +package com.faraphel.tasks_valider.connectivity.task.api + +import com.faraphel.tasks_valider.connectivity.task.session.TaskSession +import com.faraphel.tasks_valider.database.api.client.TaskEntityHttpClient +import com.faraphel.tasks_valider.database.entities.SessionEntity +import com.faraphel.tasks_valider.database.entities.error.HttpException +import com.faraphel.tasks_valider.utils.parser + + +/** + * Interface to communicate with the server session manager + */ +class TaskSessionManagerClientApi(private val client: TaskEntityHttpClient) { + /** + * Create a new session + * @param cardId the id of the user's card + * @param password the password of the user + */ + fun newFromCardId(cardId: String, password: String): TaskSession { + val response = this.client.post( + "sessions/self", + parser.toJson(mapOf( + "card_id" to cardId, + "password" to password + )) + ) + + // in case of error, notify it + if (!response.isSuccessful) + throw HttpException(response.code) + + val data = response.body.string() + + // parse the result + return parser.fromJson( + data, + TaskSession::class.java + ) + + } + + /** + * Get the current session + */ + fun getSelf(): TaskSession { + val response = this.client.get("sessions/self") + + // in case of error, notify it + if (!response.isSuccessful) + throw HttpException(response.code) + + // parse the result + return parser.fromJson( + response.body.string(), + TaskSession::class.java + ) + } +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerApi.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerServerApi.kt similarity index 80% rename from app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerApi.kt rename to app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerServerApi.kt index 6d6f055..7b57fdb 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerApi.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/api/TaskSessionManagerServerApi.kt @@ -4,6 +4,8 @@ import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission import com.faraphel.tasks_valider.connectivity.task.session.TaskSession import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager import com.faraphel.tasks_valider.database.TaskDatabase +import com.faraphel.tasks_valider.database.entities.PersonEntity +import com.faraphel.tasks_valider.utils.getBody import com.faraphel.tasks_valider.utils.parser import com.google.gson.reflect.TypeToken import fi.iki.elonen.NanoHTTPD @@ -12,7 +14,7 @@ import fi.iki.elonen.NanoHTTPD /** * the HTTP API for the session manager */ -class TaskSessionManagerApi( +class TaskSessionManagerServerApi( private val sessionManager: TaskSessionManager, private val database: TaskDatabase ) { @@ -72,25 +74,44 @@ class TaskSessionManagerApi( NanoHTTPD.Method.POST -> { // get the user identifiers val identifiers: Map = parser.fromJson( - httpSession.inputStream.bufferedReader().readText(), + httpSession.getBody(), object : TypeToken>() {}.type ) + val person: PersonEntity + // check for the id - if (!identifiers.contains("id")) + if (identifiers.contains("id")) { + // get the id of the user (if invalid, return an error) + val personId: Long = identifiers["id"]!!.toLongOrNull() + ?: return NanoHTTPD.newFixedLengthResponse( + NanoHTTPD.Response.Status.BAD_REQUEST, + "text/plain", + "Invalid id" + ) + + // check if the identifiers are correct + person = this.database.personDao().getById(personId) + ?: return NanoHTTPD.newFixedLengthResponse( + NanoHTTPD.Response.Status.BAD_REQUEST, + "text/plain", + "No person with this id" + ) + } else if (identifiers.contains("card_id")) { + // check if the identifiers are correct + person = this.database.personDao().getByCardId(identifiers["card_id"]!!) + ?: return NanoHTTPD.newFixedLengthResponse( + NanoHTTPD.Response.Status.BAD_REQUEST, + "text/plain", + "No person with this id" + ) + } else { return NanoHTTPD.newFixedLengthResponse( NanoHTTPD.Response.Status.BAD_REQUEST, "text/plain", - "Missing id" - ) - - // get the id of the user (if invalid, return an error) - val personId: Long = identifiers["id"]!!.toLongOrNull() - ?: return NanoHTTPD.newFixedLengthResponse( - NanoHTTPD.Response.Status.BAD_REQUEST, - "text/plain", - "Invalid id" + "Missing id or card_id" ) + } // check for the password if (!identifiers.contains("password")) @@ -100,14 +121,6 @@ class TaskSessionManagerApi( "Missing password" ) - // check if the identifiers are correct - val person = this.database.personDao().getById(personId) - ?: return NanoHTTPD.newFixedLengthResponse( - NanoHTTPD.Response.Status.BAD_REQUEST, - "text/plain", - "No person with this id" - ) - // check if the password is correct if (!person.checkPassword(identifiers["password"]!!)) return NanoHTTPD.newFixedLengthResponse( @@ -119,11 +132,11 @@ class TaskSessionManagerApi( // create a new session for the userJHH val (sessionToken, session) = this.sessionManager.newSessionData(person) - // create the response + // create the response with the session data val response = NanoHTTPD.newFixedLengthResponse( NanoHTTPD.Response.Status.OK, - "text/plain", - "Session updated" + "application/json", + parser.toJson(session) ) // set the session token in the cookies diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/session/TaskSession.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/session/TaskSession.kt index 99998cb..e8650ed 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/session/TaskSession.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/task/session/TaskSession.kt @@ -1,6 +1,7 @@ package com.faraphel.tasks_valider.connectivity.task.session import com.faraphel.tasks_valider.database.entities.PersonEntity +import com.google.gson.annotations.Expose import kotlinx.serialization.Serializable @@ -9,5 +10,5 @@ import kotlinx.serialization.Serializable */ @Serializable data class TaskSession( - val person: PersonEntity, -) \ No newline at end of file + @Expose val person: PersonEntity, +) diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/dao/PersonDao.kt b/app/src/main/java/com/faraphel/tasks_valider/database/dao/PersonDao.kt index 7b481e8..84cb348 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/dao/PersonDao.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/dao/PersonDao.kt @@ -18,6 +18,12 @@ interface PersonDao : BaseTaskDao { @Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE id = :id") fun getById(id: Long): PersonEntity? + /** + * Get the object from its card identifier + */ + @Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE card_id = :cardId") + fun getByCardId(cardId: String): PersonEntity? + @Query( "SELECT * FROM ${PersonEntity.TABLE_NAME} " + "WHERE id IN (" + diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/ClassEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/ClassEntity.kt index 97eb47e..f2f84c6 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/ClassEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/ClassEntity.kt @@ -4,12 +4,13 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose @Entity(tableName = ClassEntity.TABLE_NAME) data class ClassEntity ( - @ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0, - @ColumnInfo("name") val name: String, + @ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0, + @ColumnInfo("name") @Expose val name: String, ) : BaseEntity() { companion object { const val TABLE_NAME = "classes" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/PersonEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/PersonEntity.kt index 0e62606..4fc8972 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/PersonEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/PersonEntity.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.PrimaryKey import com.faraphel.tasks_valider.connectivity.task.session.TaskRole import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose import kotlinx.serialization.Serializable import java.security.MessageDigest import java.util.* @@ -12,12 +13,13 @@ import java.util.* @Serializable @Entity(tableName = PersonEntity.TABLE_NAME) data class PersonEntity ( - @ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0, - @ColumnInfo("first_name") val firstName: String, - @ColumnInfo("last_name") val lastName: String, - @ColumnInfo("card_id") val cardId: String? = null, + + @ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0, + @ColumnInfo("first_name") @Expose val firstName: String, + @ColumnInfo("last_name") @Expose val lastName: String, + @ColumnInfo("card_id") @Expose val cardId: String? = null, @ColumnInfo("password_hash") val passwordHash: String? = null, - @ColumnInfo("role") val role: TaskRole = TaskRole.STUDENT, + @ColumnInfo("role") @Expose val role: TaskRole = TaskRole.STUDENT, ) : BaseEntity() { companion object { const val TABLE_NAME = "persons" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationClassPersonEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationClassPersonEntity.kt index 06c024a..0a68512 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationClassPersonEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationClassPersonEntity.kt @@ -4,6 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.ForeignKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose @Entity( tableName = RelationClassPersonEntity.TABLE_NAME, @@ -27,8 +28,8 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity ] ) data class RelationClassPersonEntity ( - @ColumnInfo("student_id", index = true) val studentId: Long, - @ColumnInfo("class_id", index = true) val classId: Long, + @ColumnInfo("student_id", index = true) @Expose val studentId: Long, + @ColumnInfo("class_id", index = true) @Expose val classId: Long, ) : BaseEntity() { companion object { const val TABLE_NAME = "relation_class_person" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationPersonSessionSubjectEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationPersonSessionSubjectEntity.kt index d39a8e9..109b2be 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationPersonSessionSubjectEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/RelationPersonSessionSubjectEntity.kt @@ -4,6 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.ForeignKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose /** @@ -38,9 +39,9 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity ] ) data class RelationPersonSessionSubjectEntity ( - @ColumnInfo("student_id", index = true) val studentId: Long, - @ColumnInfo("session_id", index = true) val sessionId: Long, - @ColumnInfo("subject_id", index = true) val subjectId: Long, + @ColumnInfo("student_id", index = true) @Expose val studentId: Long, + @ColumnInfo("session_id", index = true) @Expose val sessionId: Long, + @ColumnInfo("subject_id", index = true) @Expose val subjectId: Long, ) : BaseEntity() { companion object { const val TABLE_NAME = "relation_person_session_subject" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/SessionEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/SessionEntity.kt index 0f2edf4..41e9648 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/SessionEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/SessionEntity.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.PrimaryKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose import java.time.Instant @Entity( @@ -19,9 +20,9 @@ import java.time.Instant ] ) data class SessionEntity ( - @ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0, - @ColumnInfo("name") val name: String? = null, - @ColumnInfo("start") val start: Instant, + @ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0, + @ColumnInfo("name") @Expose val name: String? = null, + @ColumnInfo("start") @Expose val start: Instant, @ColumnInfo("class_id", index = true) val classId: Long? = null, ) : BaseEntity() { diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/SubjectEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/SubjectEntity.kt index ee8aa83..d104fed 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/SubjectEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/SubjectEntity.kt @@ -4,11 +4,12 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose @Entity(tableName = SubjectEntity.TABLE_NAME) data class SubjectEntity ( - @ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0, - @ColumnInfo("name") val name: String, + @ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0, + @ColumnInfo("name") @Expose val name: String, ) : BaseEntity() { companion object { const val TABLE_NAME = "subjects" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/TaskEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/TaskEntity.kt index 255fce3..99bf154 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/TaskEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/TaskEntity.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.PrimaryKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose @Entity( tableName = TaskEntity.TABLE_NAME, @@ -18,12 +19,12 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity ] ) data class TaskEntity ( - @ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0, - @ColumnInfo("title") val title: String, - @ColumnInfo("description") val description: String? = null, - @ColumnInfo("order") val order: Int, ///< the order of the task in the list of the subject + @ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0, + @ColumnInfo("title") @Expose val title: String, + @ColumnInfo("description") @Expose val description: String? = null, + @ColumnInfo("order") @Expose val order: Int, ///< the order of the task in the list of the subject - @ColumnInfo("subject_id", index = true) val subjectId: Long, + @ColumnInfo("subject_id", index = true) @Expose val subjectId: Long, ) : BaseEntity() { companion object { const val TABLE_NAME = "tasks" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/ValidationEntity.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/ValidationEntity.kt index 7e489ca..0ad2f8b 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/ValidationEntity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/ValidationEntity.kt @@ -4,6 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.ForeignKey import com.faraphel.tasks_valider.database.entities.base.BaseEntity +import com.google.gson.annotations.Expose import java.time.Instant @Entity( @@ -35,11 +36,11 @@ import java.time.Instant ] ) data class ValidationEntity ( - @ColumnInfo("teacher_id", index = true) val teacherId: Long, - @ColumnInfo("student_id", index = true) val studentId: Long, - @ColumnInfo("task_id", index = true) val taskId: Long, + @ColumnInfo("teacher_id", index = true) @Expose val teacherId: Long, + @ColumnInfo("student_id", index = true) @Expose val studentId: Long, + @ColumnInfo("task_id", index = true) @Expose val taskId: Long, - @ColumnInfo("date") val date: Instant, + @ColumnInfo("date") @Expose val date: Instant, ) : BaseEntity() { companion object { const val TABLE_NAME = "validations" diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/entities/error/HttpException.kt b/app/src/main/java/com/faraphel/tasks_valider/database/entities/error/HttpException.kt index 0c28d91..dae2aa8 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/entities/error/HttpException.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/entities/error/HttpException.kt @@ -3,4 +3,8 @@ package com.faraphel.tasks_valider.database.entities.error class HttpException( private val code: Int, -) : Exception("Http Exception: $code") \ No newline at end of file +) : Exception("Http Exception: $code") { + fun getCode(): Int { + return code + } +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt new file mode 100644 index 0000000..98bbf25 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt @@ -0,0 +1,146 @@ +package com.faraphel.tasks_valider.ui.screen.authentication + +import android.app.Activity +import android.widget.Toast +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.faraphel.tasks_valider.connectivity.task.TaskClient +import com.faraphel.tasks_valider.connectivity.task.session.TaskSession +import com.faraphel.tasks_valider.database.entities.error.HttpException +import com.faraphel.tasks_valider.ui.screen.scan.qr.ScanBarcodeScreen +import com.journeyapps.barcodescanner.BarcodeResult +import okhttp3.HttpUrl.Companion.toHttpUrl + + +/** + * Authentification screen where the client can give his information + */ +@Composable +fun AuthenticationClientScreen(activity: Activity, client: TaskClient, session: MutableState) { + val controller = rememberNavController() + val barcode = remember { mutableStateOf(null) } + + NavHost(navController = controller, startDestination = "main") { + composable("main") { + AuthenticationClientContent(activity, controller, client, session, barcode) + } + composable("scan") { + if (barcode.value == null) ScanBarcodeScreen(activity, barcode) + else controller.navigate("main") + } + } +} + + +@Composable +fun AuthenticationClientContent( + activity: Activity, + controller: NavController, + client: TaskClient, + session: MutableState, + barcode: MutableState, +) { + val cardId = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + + // check if the barcode contain information about the card + + var defaultCardId = "" + if (barcode.value != null) { + val studentUrl = barcode.value!!.text.toHttpUrl() + cardId.value = studentUrl.pathSegments[0] + } + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // title + Text( + text = "Authentication", + fontSize = 32.sp + ) + + // separator + Spacer(modifier = Modifier.height(24.dp)) + + // card identifier + Row { + // text + TextField( + value = cardId.value, + placeholder = { Text("Card Id") }, + onValueChange = { text -> cardId.value = text }, + ) + // button to scan the card + Button(onClick = { + barcode.value = null + controller.navigate("scan") + }) { + Text("Scan") + } + } + + // password + TextField( + value = password.value, + visualTransformation = PasswordVisualTransformation(), + placeholder = { Text("Password") }, + onValueChange = { text -> password.value = text }, + ) + + // separator + Spacer(modifier = Modifier.height(24.dp)) + + // submit button + + Button(onClick = { + Thread { authenticate(activity, client, cardId.value, password.value, session) }.start() + }) { + Text("Submit") + } + } +} + +fun authenticate( + activity: Activity, + client: TaskClient, + cardId: String, + password: String, + session: MutableState +) { + try { + // try to get a session from the identifiers + session.value = client.session.newFromCardId(cardId, password) + } catch (exception: HttpException) { + // in case of error, show a message to the user + when (exception.getCode()) { + 401 -> { + activity.runOnUiThread { + Toast.makeText(activity, "Invalid card id or password", Toast.LENGTH_SHORT).show() + } + } + else -> { + activity.runOnUiThread { + Toast.makeText(activity, "Unknown error: $exception", Toast.LENGTH_SHORT).show() + } + } + } + } +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt similarity index 93% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/server.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt index f9d5084..5e30ed9 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.authentification +package com.faraphel.tasks_valider.ui.screen.authentication import androidx.compose.foundation.layout.* import androidx.compose.material3.Button @@ -20,7 +20,7 @@ import com.faraphel.tasks_valider.database.entities.PersonEntity * Authentification screen where the host can give his information */ @Composable -fun AuthentificationServerScreen(personEntity: MutableState) { +fun AuthenticationServerScreen(personEntity: MutableState) { val firstName = remember { mutableStateOf("") } val lastName = remember { mutableStateOf("") } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/client.kt deleted file mode 100644 index 1c83eb0..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentification/client.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.faraphel.tasks_valider.ui.screen.authentification - -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.text.input.PasswordVisualTransformation - - -/** - * Authentification screen where the client can give his information - */ -@Composable -fun AuthentificationClientScreen() { - val cardId = remember { mutableStateOf("") } - val password = remember { mutableStateOf("") } - - Column { - // card identifier - TextField( - value = cardId.value, - onValueChange = { text -> cardId.value = text }, - ) - - // password - TextField( - value = password.value, - visualTransformation = PasswordVisualTransformation(), - onValueChange = { text -> password.value = text }, - ) - - // button - Button(onClick = { /* do something */ }) { - Text("Submit") - } - } -} diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt index 5a7927d..2f29e5d 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt @@ -1,9 +1,7 @@ package com.faraphel.tasks_valider.ui.screen.communication.internet import android.app.Activity -import android.os.Build -import androidx.annotation.RequiresApi -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.Text @@ -13,21 +11,38 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.faraphel.tasks_valider.connectivity.task.TaskClient +import com.faraphel.tasks_valider.connectivity.task.session.TaskSession +import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationClientScreen import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT +import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CommunicationInternetClientScreen(activity: Activity) { val client = remember { mutableStateOf(null) } + val session = remember { mutableStateOf(null) } - // TODO(Faraphel): fix and get a user - // if (client.value == null) CommunicationInternetClientContent(client) - // else TaskSessionScreen(activity, client.value!!, user) + // if the client is not connected, show the connection screen + if (client.value == null) + return CommunicationInternetClientContent(client) + // if the user is not authenticated, show the authentication screen + if (session.value == null) + return AuthenticationClientScreen(activity, client.value!!, session) + + // show the main screen + TaskSessionController( + activity, + client.value!!, + session.value!!.person, + ) } @@ -36,18 +51,31 @@ fun CommunicationInternetClientContent(client: MutableState) { val serverAddress = remember { mutableStateOf(DEFAULT_SERVER_ADDRESS) } val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) } - Column { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // title + Text( + text = "Connection", + fontSize = 32.sp + ) + + // separator + Spacer(modifier = Modifier.height(24.dp)) + // server address TextField( value = serverAddress.value, - onValueChange = { text -> - serverAddress.value = text - } + placeholder = { Text("server IP") }, + onValueChange = { text -> serverAddress.value = text } ) // server port TextField( value = serverPort.intValue.toString(), + placeholder = { Text("server port") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), onValueChange = { text -> val port = text.toInt() @@ -57,6 +85,10 @@ fun CommunicationInternetClientContent(client: MutableState) { } ) + // separator + Spacer(modifier = Modifier.height(24.dp)) + + // connect button Button(onClick = { // TODO(Faraphel): check if the server is reachable client.value = TaskClient(serverAddress.value, serverPort.intValue) diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt index 0d29936..378eef5 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt @@ -27,7 +27,7 @@ import com.faraphel.tasks_valider.database.entities.ClassEntity import com.faraphel.tasks_valider.database.entities.PersonEntity import com.faraphel.tasks_valider.database.entities.SessionEntity import com.faraphel.tasks_valider.database.populateSubjectSessionPersonTest -import com.faraphel.tasks_valider.ui.screen.authentification.AuthentificationServerScreen +import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationServerScreen import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController @@ -37,7 +37,6 @@ import java.time.Instant /** * Screen for the host to configure the server */ -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CommunicationInternetServerScreen( activity: Activity, @@ -52,7 +51,7 @@ fun CommunicationInternetServerScreen( NavHost(navController = controller, startDestination = "authentication") { composable("authentication") { // if the admin person is not created, prompt the user for the admin information - if (adminPersonEntityRaw.value == null) AuthentificationServerScreen(adminPersonEntityRaw) + if (adminPersonEntityRaw.value == null) AuthenticationServerScreen(adminPersonEntityRaw) else controller.navigate("configuration") } composable("configuration") { diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt index a04f0ae..cf8d883 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt @@ -33,7 +33,6 @@ import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationW * @param activity: The activity that hosts the communication screen. * @param database: the database. */ -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase) { val controller = rememberNavController() diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/quick_validation.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/quick_validation.kt index 98eff5e..9dcd493 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/quick_validation.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/quick_validation.kt @@ -66,7 +66,7 @@ fun quickValidation( } // requests all the persons - val allPersons = client.personApi.getAll() + val allPersons = client.entities.person.getAll() // get the person with the matching card val person = allPersons.firstOrNull { person -> person.cardId == cardId } @@ -79,19 +79,19 @@ fun quickValidation( } // requests all the relation persons - subjects - val allRelationsPersonSubject = client.relationPersonSessionSubjectApi.getAll() + val allRelationsPersonSubject = client.entities.relationPersonSessionSubject.getAll() // get the corresponding relation val relationPersonSubject = allRelationsPersonSubject.first { relation -> relation.studentId == person.id } // requests all the tasks - val allTasks = client.taskApi.getAll() + val allTasks = client.entities.task.getAll() // get the corresponding tasks val tasks = allTasks .filter { task -> task.subjectId == relationPersonSubject.subjectId } .sortedBy { task -> task.order } // requests all the validations - val allValidations = client.validationApi.getAll() + val allValidations = client.entities.validation.getAll() // get the corresponding relation val validations = allValidations.filter { validation -> validation.studentId == person.id } @@ -112,7 +112,7 @@ fun quickValidation( } // create a new validation on the server - client.validationApi.save( + client.entities.validation.save( ValidationEntity( teacherId=user.id, studentId=person.id, diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/session.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/session.kt index 4b2805c..2684530 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/session.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/session.kt @@ -1,13 +1,8 @@ package com.faraphel.tasks_valider.ui.screen.task import android.app.Activity -import android.app.Activity.RESULT_OK -import android.content.Intent -import android.os.Environment import android.util.Log import android.widget.Toast -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.* import androidx.compose.material3.Button import androidx.compose.material3.Text @@ -125,7 +120,7 @@ fun refreshStudents( ) { try { // try to get all the persons in that session - students.value = client.personApi.getAll() + students.value = client.entities.person.getAll() } catch (exception: Exception) { // in case of error, show a message return activity.runOnUiThread { @@ -141,12 +136,12 @@ fun exportToFile( client: TaskClient, ) { // get all the values to export - val allPersons = client.personApi.getAll() + val allPersons = client.entities.person.getAll() val allStudents = allPersons.filter { student -> student.role == TaskRole.STUDENT } - val allRelationsStudentSessionSubject = client.relationPersonSessionSubjectApi.getAll() - val allSubjects = client.subjectApi.getAll() - val allTasks = client.taskApi.getAll() - val allValidations = client.validationApi.getAll() + val allRelationsStudentSessionSubject = client.entities.relationPersonSessionSubject.getAll() + val allSubjects = client.entities.subject.getAll() + val allTasks = client.entities.task.getAll() + val allValidations = client.entities.validation.getAll() // for each student diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt index 61af054..e14d086 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt @@ -125,7 +125,7 @@ fun refreshTasksValidations( validations: MutableState?>, ) { // try to obtain the list of subject - val allRelationsPersonSessionSubject = client.relationPersonSessionSubjectApi.getAll() + val allRelationsPersonSessionSubject = client.entities.relationPersonSessionSubject.getAll() // get the subject that the student is using val relationPersonSessionSubject = allRelationsPersonSessionSubject.firstOrNull { relation -> relation.studentId == student.id @@ -136,7 +136,7 @@ fun refreshTasksValidations( return activity.runOnUiThread { Toast.makeText(activity, "No subject assigned", Toast.LENGTH_LONG).show() } // try to obtain the list of tasks - val allTasks = client.taskApi.getAll() + val allTasks = client.entities.task.getAll() // get the tasks that are linked to this subject tasks.value = allTasks @@ -144,7 +144,7 @@ fun refreshTasksValidations( .sortedBy { task -> task.order } // try to obtain the list of validations - val allValidations = client.validationApi.getAll() + val allValidations = client.entities.validation.getAll() // filter only the interesting validations validations.value = allValidations.filter { validation -> validation.studentId == student.id && @@ -156,8 +156,8 @@ fun refreshTasksValidations( fun updateValidation(client: TaskClient, checked: Boolean, validation: ValidationEntity) { if (checked) // if the validation is not set, create it - client.validationApi.save(validation) + client.entities.validation.save(validation) else // if the validation is set, delete it - client.validationApi.delete(validation) + client.entities.validation.delete(validation) } diff --git a/app/src/main/java/com/faraphel/tasks_valider/utils/json.kt b/app/src/main/java/com/faraphel/tasks_valider/utils/json.kt index 5612d11..7c75a63 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/utils/json.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/utils/json.kt @@ -8,4 +8,5 @@ import java.time.Instant val parser: Gson = GsonBuilder() .registerTypeAdapter(Instant::class.java, InstantConverter()) + .excludeFieldsWithoutExposeAnnotation() .create() \ No newline at end of file From d74605bbb914b31f986723c19063a0e9d4799365 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 23 Jun 2024 18:36:19 +0200 Subject: [PATCH 2/7] WIP: fixing the Wi-Fi Direct feature --- .../connectivity/bwd/BwdManager.kt | 5 +- .../authentication/client.kt | 2 +- .../authentication/server.kt | 2 +- .../{ => connection}/internet/client.kt | 4 +- .../{ => connection}/internet/selection.kt | 2 +- .../{ => connection}/internet/server.kt | 4 +- .../wifiP2p/client.kt} | 2 +- .../connection/wifiP2p/selection.kt | 61 +++++++++++++++++++ .../wifiP2p/server.kt} | 2 +- .../ui/screen/communication/selection.kt | 9 +-- .../ui/screen/communication/wifiP2p/screen.kt | 37 ----------- 11 files changed, 76 insertions(+), 54 deletions(-) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/{ => communication}/authentication/client.kt (98%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/{ => communication}/authentication/server.kt (96%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/{ => connection}/internet/client.kt (94%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/{ => connection}/internet/selection.kt (95%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/{ => connection}/internet/server.kt (97%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/{wifiP2p/client/screen.kt => connection/wifiP2p/client.kt} (95%) create mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/{wifiP2p/server/screen.kt => connection/wifiP2p/server.kt} (97%) delete mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt index e1d1994..d200d0f 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt @@ -43,13 +43,13 @@ class BwdManager( */ fun fromActivity(activity: Activity): BwdManager { // check if the system support WiFi-Direct - if (this.isSupported(activity)) { + if (!this.isSupported(activity)) { Log.e("wifi-p2p", "this device does not support the WiFi-Direct feature") throw BwdNotSupportedException() } // TODO(Faraphel): more check on permissions - if ( + /* if ( activity.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || activity.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED ) { @@ -59,6 +59,7 @@ class BwdManager( PERMISSION_ACCESS_FINE_LOCATION ) } + */ // get the WiFi-Direct manager val manager = activity.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager? diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt similarity index 98% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt index 98bbf25..8859f3d 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.authentication +package com.faraphel.tasks_valider.ui.screen.communication.authentication import android.app.Activity import android.widget.Toast diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/server.kt similarity index 96% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/server.kt index 5e30ed9..de9482b 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/authentication/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/server.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.authentication +package com.faraphel.tasks_valider.ui.screen.communication.authentication import androidx.compose.foundation.layout.* import androidx.compose.material3.Button diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt similarity index 94% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt index 2f29e5d..cd53c0d 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.internet +package com.faraphel.tasks_valider.ui.screen.communication.connection.internet import android.app.Activity import androidx.compose.foundation.layout.* @@ -18,7 +18,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.faraphel.tasks_valider.connectivity.task.TaskClient import com.faraphel.tasks_valider.connectivity.task.session.TaskSession -import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationClientScreen +import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationClientScreen import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt similarity index 95% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/selection.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt index 1575f12..91247e1 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.internet +package com.faraphel.tasks_valider.ui.screen.communication.connection.internet import android.app.Activity import android.os.Build diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt similarity index 97% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt index 378eef5..6d4d179 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.internet +package com.faraphel.tasks_valider.ui.screen.communication.connection.internet import android.app.Activity import android.os.Build @@ -27,7 +27,7 @@ import com.faraphel.tasks_valider.database.entities.ClassEntity import com.faraphel.tasks_valider.database.entities.PersonEntity import com.faraphel.tasks_valider.database.entities.SessionEntity import com.faraphel.tasks_valider.database.populateSubjectSessionPersonTest -import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationServerScreen +import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationServerScreen import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt similarity index 95% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt index b2cc732..106b866 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.client +package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p import android.app.Activity import android.net.wifi.p2p.WifiP2pConfig diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt new file mode 100644 index 0000000..30b967f --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt @@ -0,0 +1,61 @@ +package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p + +import android.app.Activity +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.faraphel.tasks_valider.connectivity.bwd.BwdManager + + +@Composable +fun CommunicationWifiP2pScreen(activity: Activity) { + val controller = rememberNavController() + + var bwdManager: BwdManager? = null + + LaunchedEffect(true) { + // start the BWD manager + bwdManager = BwdManager.fromActivity(activity) + } + + NavHost(navController = controller, startDestination = "mode") { + composable("mode") { CommunicationWifiP2pSelectContent(controller) } + // composable("client") { CommunicationWifiP2pClientScreen(activity, bwdManager) } + composable("server") { CommunicationWifiP2pServerScreen(activity, bwdManager!!) } + } +} + + + +@Composable +fun CommunicationWifiP2pSelectContent(controller: NavController) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // title + Text( + text = "Role", + fontSize = 32.sp + ) + + // separator + Spacer(modifier = Modifier.height(24.dp)) + + // client mode + Button(onClick = { controller.navigate("client") }) { Text("Client") } + // server mode + Button(onClick = { controller.navigate("server") }) { Text("Server") } + } +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt similarity index 97% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt index b3eba6d..20d428d 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server +package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p import android.app.Activity import androidx.compose.runtime.Composable diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt index cf8d883..5190732 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt @@ -1,9 +1,7 @@ package com.faraphel.tasks_valider.ui.screen.communication import android.app.Activity -import android.os.Build import android.widget.Toast -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.* import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -21,8 +19,8 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.bwd.BwdManager import com.faraphel.tasks_valider.database.TaskDatabase -import com.faraphel.tasks_valider.ui.screen.communication.internet.CommunicationInternetSelectScreen -import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationWifiP2pScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.CommunicationInternetSelectScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.CommunicationWifiP2pScreen /** @@ -48,8 +46,7 @@ fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase) CommunicationInternetSelectScreen(activity, database) } composable("wifi-p2p") { - val bwdManager = BwdManager.fromActivity(activity) - CommunicationWifiP2pScreen(activity, bwdManager) + CommunicationWifiP2pScreen(activity) } } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt deleted file mode 100644 index c7d4b58..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p - -import android.app.Activity -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.navigation.NavController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import com.faraphel.tasks_valider.connectivity.bwd.BwdManager -import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.client.CommunicationWifiP2pClientScreen -import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server.CommunicationWifiP2pServerScreen - - -@Composable -fun CommunicationWifiP2pScreen(activity: Activity, bwdManager: BwdManager) { - val controller = rememberNavController() - - NavHost(navController = controller, startDestination = "mode") { - composable("mode") { CommunicationWifiP2pSelectContent(controller) } - composable("client") { CommunicationWifiP2pClientScreen(activity, bwdManager) } - composable("server") { CommunicationWifiP2pServerScreen(activity, bwdManager) } - } -} - - -@Composable -fun CommunicationWifiP2pSelectContent(controller: NavController) { - Column { - // client mode - Button(onClick = { controller.navigate("client") }) { Text("Client") } - // server mode - Button(onClick = { controller.navigate("server") }) { Text("Server") } - } -} From 53d37d86ab3ec0706e9130f41ed141126e3722f1 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Mon, 24 Jun 2024 22:00:56 +0200 Subject: [PATCH 3/7] fixed the Wi-Fi direct server creation --- .../tasks_valider/connectivity/bwd/README.md | 4 +- .../connection/internet/selection.kt | 1 - .../connection/internet/server.kt | 10 +- .../connection/wifiP2p/selection.kt | 16 +- .../connection/wifiP2p/server.kt | 234 ++++++++++++------ .../ui/screen/communication/selection.kt | 2 +- 6 files changed, 171 insertions(+), 96 deletions(-) diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/README.md b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/README.md index 4e0acc5..b94ec29 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/README.md +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/README.md @@ -1,6 +1,6 @@ -# Better WiFi-Direct (BWD) +# Better Wi-Fi Direct (BWD) -This package contain code to improve the base WiFi-Direct implementation. +This package contain code to improve the base Wi-Fi Direct implementation. The base have some issue, like an abusive usage of listener, error code and events that make using it very impractical. diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt index 91247e1..7f6e353 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt @@ -18,7 +18,6 @@ import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.database.TaskDatabase -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CommunicationInternetSelectScreen(activity: Activity, database: TaskDatabase) { val controller = rememberNavController() diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt index 6d4d179..9021139 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt @@ -1,9 +1,7 @@ package com.faraphel.tasks_valider.ui.screen.communication.connection.internet import android.app.Activity -import android.os.Build import android.util.Log -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button @@ -75,7 +73,6 @@ fun CommunicationInternetServerScreen( } -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CommunicationInternetServerContent( database: TaskDatabase, @@ -182,12 +179,7 @@ fun CommunicationInternetServerContent( val session = database.sessionDao().getById(sessionId)!! // TODO(Faraphel): remove, this is a test function - Thread { - populateSubjectSessionPersonTest(database, session) - }.let { thread -> - thread.start() - thread.join() - } + populateSubjectSessionPersonTest(database, session) // Create the server Log.i("room-server", "creating the server") diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt index 30b967f..896a262 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt @@ -6,6 +6,7 @@ import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -15,23 +16,20 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.bwd.BwdManager +import com.faraphel.tasks_valider.database.TaskDatabase @Composable -fun CommunicationWifiP2pScreen(activity: Activity) { +fun CommunicationWifiP2pScreen(activity: Activity, database: TaskDatabase) { val controller = rememberNavController() - var bwdManager: BwdManager? = null - - LaunchedEffect(true) { - // start the BWD manager - bwdManager = BwdManager.fromActivity(activity) - } + // create the Wi-Fi Direct manager + val bwdManager = remember { BwdManager.fromActivity(activity) } NavHost(navController = controller, startDestination = "mode") { composable("mode") { CommunicationWifiP2pSelectContent(controller) } - // composable("client") { CommunicationWifiP2pClientScreen(activity, bwdManager) } - composable("server") { CommunicationWifiP2pServerScreen(activity, bwdManager!!) } + composable("client") { CommunicationWifiP2pClientScreen(activity, bwdManager) } + composable("server") { CommunicationWifiP2pServerScreen(activity, database, bwdManager) } } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt index 20d428d..36cdf26 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt @@ -1,18 +1,72 @@ package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p import android.app.Activity -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import android.util.Log +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.bwd.BwdManager import com.faraphel.tasks_valider.connectivity.task.TaskClient +import com.faraphel.tasks_valider.connectivity.task.TaskServer +import com.faraphel.tasks_valider.database.TaskDatabase +import com.faraphel.tasks_valider.database.entities.ClassEntity +import com.faraphel.tasks_valider.database.entities.PersonEntity +import com.faraphel.tasks_valider.database.entities.SessionEntity +import com.faraphel.tasks_valider.database.populateSubjectSessionPersonTest +import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT +import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT +import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationServerScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.CommunicationInternetServerContent +import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController +import java.time.Instant @Composable -fun CommunicationWifiP2pServerScreen(activity: Activity, bwdManager: BwdManager) { +fun CommunicationWifiP2pServerScreen( + activity: Activity, + database: TaskDatabase, + bwdManager: BwdManager +) { + val controller = rememberNavController() + + val adminPersonEntityRaw = remember { mutableStateOf(null) } + val adminPersonEntity = remember { mutableStateOf(null) } val client = remember { mutableStateOf(null) } + NavHost(navController = controller, startDestination = "authentication") { + composable("authentication") { + // if the admin person is not created, prompt the user for the admin information + if (adminPersonEntityRaw.value == null) AuthenticationServerScreen(adminPersonEntityRaw) + else controller.navigate("configuration") + } + composable("configuration") { + if (client.value == null) + CommunicationWifiP2pServerContent( + database, + bwdManager, + adminPersonEntityRaw, + adminPersonEntity, + client, + ) + else controller.navigate("session") + } + composable("session") { + TaskSessionController( + activity, + client.value!!, + adminPersonEntity.value!! + ) + } + } // TODO(Faraphel): fix and get a user // if the server is not created, prompt the user for the server configuration // if (client.value == null) CommunicationWifiP2pServerContent(activity, bwfManager, client) @@ -23,83 +77,115 @@ fun CommunicationWifiP2pServerScreen(activity: Activity, bwdManager: BwdManager) @Composable fun CommunicationWifiP2pServerContent( - activity: Activity, + database: TaskDatabase, bwdManager: BwdManager, + adminPersonEntityRaw: MutableState, + adminPersonEntity: MutableState, client: MutableState ) { - /* - val expandedStudentList = remember { mutableStateOf(false) } - val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) } + val classes = remember { mutableStateOf?>(null) } + val selectedClass = remember { mutableStateOf(null) } + val areClassesExpanded = remember { mutableStateOf(false) } - Column { - // student list - Button(onClick = { expandedStudentList.value = !expandedStudentList.value }) { - Text(text = "Select Students List") - } - DropdownMenu( - expanded = expandedStudentList.value, - onDismissRequest = { expandedStudentList.value = false } - ) { - DropdownMenuItem( - text = { Text("ISRI") }, - onClick = {} - ) - DropdownMenuItem( - text = { Text("MIAGE") }, - onClick = {} - ) - // TODO(Faraphel): student lists should be loaded from the database or a file - } + LaunchedEffect(true) { + // refresh the list of classes + Thread { refreshClasses(database, classes) }.start() + } - // server port - TextField( - value = serverPort.intValue.toString(), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - onValueChange = { text -> - val port = text.toInt() - if (port in RANGE_SERVER_PORT) { - serverPort.intValue = port - } - } + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // title + Text( + text = "New Session", + fontSize = 32.sp ) - Button(onClick = { - // TODO(Faraphel): should be merged with the internet server + // separator + Spacer(modifier = Modifier.height(24.dp)) - // Reset the database | TODO(Faraphel): only for testing purpose - activity.deleteDatabase("local") - - // Create the database - val database = Room.databaseBuilder( - activity, - TaskDatabase::class.java, - "local" - ).build() - - // Create the admin - // TODO: the admin should be created from the card reader - val adminPersonEntity = PersonEntity( - "admin", - "admin", - "123456789", - "admin", - - ) - - // Insert the admin in the database - database.personDao().insert(adminPersonEntity) - - bwfManager.recreateGroup { - // Create the server - val server = TaskServer(serverPort.intValue, database, adminPersonEntity) - server.start() - - // Get the client from the server - client.value = server.getAdminClient() + // classes + Row(verticalAlignment = Alignment.CenterVertically) { + // description + Text(text = "Class", fontSize = 12.sp) + // separator + Spacer(modifier = Modifier.width(width = 12.dp)) + // selector + Button(onClick = { areClassesExpanded.value = !areClassesExpanded.value }) { + // display the selected class, if selected + if (selectedClass.value != null) Text(text = selectedClass.value!!.name) + else Text(text = "") + } + + // class selector + DropdownMenu( + expanded = areClassesExpanded.value, + onDismissRequest = { areClassesExpanded.value = false } + ) { + // TODO(Faraphel): student lists should be loaded from the database or a file + classes.value?.forEach { class_ -> + DropdownMenuItem( + text = { Text(class_.name) }, + onClick = { + selectedClass.value = class_ + areClassesExpanded.value = false + } + ) + } } - }) { - Text("Create") } + + // check if a class is selected + if (selectedClass.value != null) + // button to create the server + Button(onClick = { + Thread { // a thread is used for networking + // Insert the admin in the database and get its id + val adminPersonEntityId = database.personDao().insert(adminPersonEntityRaw.value!!) + adminPersonEntity.value = database.personDao().getById(adminPersonEntityId)!! + + // Create a new session + // TODO(Faraphel): name + val sessionId = database.sessionDao().insert( + SessionEntity( + name="NOM", + start= Instant.now(), + classId=selectedClass.value!!.id, + ) + ) + val session = database.sessionDao().getById(sessionId)!! + + // TODO(Faraphel): remove, this is a test function + populateSubjectSessionPersonTest(database, session) + + // create a new Wi-Fi Direct group + bwdManager.recreateGroup { + // Create the server + Log.i("room-server", "creating the server") + val server = TaskServer( + DEFAULT_SERVER_PORT, + database, + session, + adminPersonEntity.value!!, + ) + server.start() + + // Get the client from the server + client.value = server.getAdminClient() + } + }.start() + }) { + Text("Create") + } } - */ -} \ No newline at end of file +} + + +/** + * Refresh the list of classes + */ +fun refreshClasses(database: TaskDatabase, classes: MutableState?>) { + classes.value = database.classDao().getAll() +} diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt index 5190732..86aedf3 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt @@ -46,7 +46,7 @@ fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase) CommunicationInternetSelectScreen(activity, database) } composable("wifi-p2p") { - CommunicationWifiP2pScreen(activity) + CommunicationWifiP2pScreen(activity, database) } } } From c6b11effe345b88a5bef61ed9a36221f19c282e5 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sat, 29 Jun 2024 03:15:47 +0200 Subject: [PATCH 4/7] fixed the Wi-Fi Direct client feature --- README.md | 13 +++- app/src/main/AndroidManifest.xml | 3 +- .../connectivity/bwd/BwdManager.kt | 12 ++- .../connection/internet/{ => role}/client.kt | 2 +- .../connection/internet/{ => role}/server.kt | 2 +- .../connection/internet/selection.kt | 4 +- .../connection/wifiP2p/client.kt | 57 -------------- .../connection/wifiP2p/role/client.kt | 76 +++++++++++++++++++ .../connection/wifiP2p/{ => role}/server.kt | 6 +- .../connection/wifiP2p/selection.kt | 5 +- .../ui/screen/communication/selection.kt | 4 +- 11 files changed, 110 insertions(+), 74 deletions(-) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/{ => role}/client.kt (99%) rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/{ => role}/server.kt (99%) delete mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt create mode 100644 app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt rename app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/{ => role}/server.kt (95%) diff --git a/README.md b/README.md index c122a9a..eff70fe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ -# Study-M1-PDS +# Master 1 - Projet de Spécialité -(Université) - Projet De Spécialité +Ce projet consiste en une application Android permettant à des enseignants de créer des session de cours où un ensemble +d'élève est assigné à des tâches de sujet différent qui peuvent être validé collaborativement. + +Il est possible d'utiliser le QR code des cartes étudiantes afin de substituer l'identifiant d'un étudiant et de +pouvoir valider rapidement les tâches d'un élève. + +# Build + +1. Cloner le projet `git clone https://git.faraphel.fr/study-faraphel/M1-PDS` +2. Ouvrer le dans Android Studio ou Intellij IDEA \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 32f3c79..c459751 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,7 +48,8 @@ + android:theme="@style/Theme.Tasksvalider" + android:screenOrientation="portrait"> diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt index d200d0f..97924cf 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwd/BwdManager.kt @@ -1,6 +1,7 @@ package com.faraphel.tasks_valider.connectivity.bwd import android.Manifest +import android.annotation.SuppressLint import android.app.Activity import android.content.BroadcastReceiver import android.content.Context @@ -41,6 +42,7 @@ class BwdManager( * Create a new BwfManager from an activity. * @param activity The activity to create the manager from */ + @SuppressLint("UnspecifiedRegisterReceiverFlag") fun fromActivity(activity: Activity): BwdManager { // check if the system support WiFi-Direct if (!this.isSupported(activity)) { @@ -67,9 +69,14 @@ class BwdManager( // get the WiFi-Direct channel val channel = manager.initialize(activity, activity.mainLooper, null) - return BwdManager(manager, channel) + + // create the manager + val bwdManager = BwdManager(manager, channel) - // NOTE(Faraphel): the broadcast receiver should be registered in the activity onResume + // make the manager receive the application intents + activity.registerReceiver(bwdManager, ALL_INTENT_FILTER) + + return bwdManager } } @@ -174,6 +181,7 @@ class BwdManager( val stateConnectionInfo = mutableStateOf(null) val statePeers = mutableStateOf(null) + override fun onReceive(context: Context?, intent: Intent?) { // ignore empty intent if (intent == null) diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt similarity index 99% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt index cd53c0d..05b6565 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.connection.internet +package com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role import android.app.Activity import androidx.compose.foundation.layout.* diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/server.kt similarity index 99% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/server.kt index 9021139..9fb8127 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/server.kt @@ -1,4 +1,4 @@ -package com.faraphel.tasks_valider.ui.screen.communication.connection.internet +package com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role import android.app.Activity import android.util.Log diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt index 7f6e353..5d4a0eb 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/selection.kt @@ -1,8 +1,6 @@ package com.faraphel.tasks_valider.ui.screen.communication.connection.internet import android.app.Activity -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.* import androidx.compose.material3.Button import androidx.compose.material3.Text @@ -16,6 +14,8 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.database.TaskDatabase +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role.CommunicationInternetClientScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role.CommunicationInternetServerScreen @Composable diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt deleted file mode 100644 index 106b866..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/client.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p - -import android.app.Activity -import android.net.wifi.p2p.WifiP2pConfig -import android.net.wifi.p2p.WifiP2pDevice -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import com.faraphel.tasks_valider.connectivity.bwd.BwdManager -import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget - - -@Composable -fun CommunicationWifiP2pClientScreen(activity: Activity, bwdManager: BwdManager) { - val selectedDevice = remember { mutableStateOf(null) } - val isConnected = remember { mutableStateOf(false) } - - // if connected, show the task group screen - if (isConnected.value) { - // TaskGroupScreen(activity, null) - // TODO(Faraphel): finish the connection - return - } - - - // if the device is selected but not connected, try to connect - if (selectedDevice.value != null) { - // TODO(Faraphel): error handling - val config = WifiP2pConfig().apply { - deviceAddress = selectedDevice.value!!.deviceAddress - } - bwdManager.connect(config) { - isConnected.value = true - } - return - } - - // display the list of devices - CommunicationWifiP2pClientContent(bwdManager, selectedDevice) -} - - -@Composable -fun CommunicationWifiP2pClientContent( - bwdManager: BwdManager, - selectedDevice: MutableState -) { - Column { - WifiP2pDeviceListWidget( - peers = bwdManager.statePeers.value, - filter = { device: WifiP2pDevice -> device.isGroupOwner }, - selectedDevice, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt new file mode 100644 index 0000000..90d9c38 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt @@ -0,0 +1,76 @@ +package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.role + +import android.app.Activity +import android.net.wifi.p2p.WifiP2pConfig +import android.net.wifi.p2p.WifiP2pDevice +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.* +import com.faraphel.tasks_valider.connectivity.bwd.BwdManager +import com.faraphel.tasks_valider.connectivity.task.TaskClient +import com.faraphel.tasks_valider.connectivity.task.session.TaskSession +import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT +import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationClientScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role.CommunicationInternetClientContent +import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController +import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen +import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget + + +@Composable +fun CommunicationWifiP2pClientScreen(activity: Activity, bwdManager: BwdManager) { + val client = remember { mutableStateOf(null) } + val session = remember { mutableStateOf(null) } + + // if the client is not connected, show the connection screen + if (client.value == null) + return CommunicationWifiP2pClientContent(client, bwdManager) + // if the user is not authenticated, show the authentication screen + if (session.value == null) + return AuthenticationClientScreen(activity, client.value!!, session) + + // show the main screen + TaskSessionController( + activity, + client.value!!, + session.value!!.person, + ) +} + + +@Composable +fun CommunicationWifiP2pClientContent( + client: MutableState, + bwdManager: BwdManager, +) { + val selectedDevice = remember { mutableStateOf(null) } + + if (selectedDevice.value == null) { + Column { + WifiP2pDeviceListWidget( + peers = bwdManager.statePeers.value, + filter = { device: WifiP2pDevice -> device.isGroupOwner }, + selectedDevice, + ) + } + + LaunchedEffect(true) { + // look for new peers + bwdManager.discoverPeers() + } + + return + } + + val config = WifiP2pConfig().apply { + deviceAddress = selectedDevice.value!!.deviceAddress + } + bwdManager.connect(config) { + bwdManager.requestConnectionInfo { connectionInfo -> + // TODO(Faraphel): check if the server is reachable + client.value = TaskClient( + connectionInfo.groupOwnerAddress.toString(), + DEFAULT_SERVER_PORT + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/server.kt similarity index 95% rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/server.kt index 36cdf26..8ba0cd6 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/server.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/server.kt @@ -1,14 +1,12 @@ -package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p +package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.role import android.app.Activity import android.util.Log import androidx.compose.foundation.layout.* -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.compose.NavHost @@ -23,9 +21,7 @@ import com.faraphel.tasks_valider.database.entities.PersonEntity import com.faraphel.tasks_valider.database.entities.SessionEntity import com.faraphel.tasks_valider.database.populateSubjectSessionPersonTest import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT -import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationServerScreen -import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.CommunicationInternetServerContent import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController import java.time.Instant diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt index 896a262..928f240 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/selection.kt @@ -1,11 +1,11 @@ package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p +import android.annotation.SuppressLint import android.app.Activity import androidx.compose.foundation.layout.* import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -16,7 +16,10 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.bwd.BwdManager +import com.faraphel.tasks_valider.connectivity.bwd.BwdManager.Companion.ALL_INTENT_FILTER import com.faraphel.tasks_valider.database.TaskDatabase +import com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.role.CommunicationWifiP2pClientScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.role.CommunicationWifiP2pServerScreen @Composable diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt index 86aedf3..1750464 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/selection.kt @@ -88,10 +88,10 @@ fun CommunicationSelectContent(controller: NavController, activity: Activity) { // if the WiFi-Direct is supported, navigate to the WiFi-Direct screen if (isWifiP2pSupported) controller.navigate("wifi-p2p") // if the WiFi-Direct is not supported, show a toast message - else Toast.makeText(activity, "WiFi-Direct is not supported on this device", Toast.LENGTH_SHORT).show() + else Toast.makeText(activity, "Wi-Fi Direct is not supported on this device", Toast.LENGTH_SHORT).show() } ) { - Text("WiFi-Direct") + Text("Wi-Fi Direct") } } } From 229cf816e3ecb99b3565aaf851290896cfcbcc7c Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 30 Jun 2024 11:44:48 +0200 Subject: [PATCH 5/7] greatly improved application stability when connecting to a Wi-Fi direct server --- .../communication/authentication/client.kt | 5 ++++ .../connection/wifiP2p/role/client.kt | 18 ++++++++++--- .../connectivity/WifiP2pDeviceListWidget.kt | 25 ++++++++++++++++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt index 8859f3d..7c49317 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/authentication/client.kt @@ -25,6 +25,7 @@ import com.faraphel.tasks_valider.database.entities.error.HttpException import com.faraphel.tasks_valider.ui.screen.scan.qr.ScanBarcodeScreen import com.journeyapps.barcodescanner.BarcodeResult import okhttp3.HttpUrl.Companion.toHttpUrl +import java.net.ConnectException /** @@ -142,5 +143,9 @@ fun authenticate( } } } + } catch (exception: ConnectException) { + activity.runOnUiThread { + Toast.makeText(activity, "Could not connect to the server: $exception", Toast.LENGTH_SHORT).show() + } } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt index 90d9c38..a823f55 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt @@ -3,6 +3,7 @@ package com.faraphel.tasks_valider.ui.screen.communication.connection.wifiP2p.ro import android.app.Activity import android.net.wifi.p2p.WifiP2pConfig import android.net.wifi.p2p.WifiP2pDevice +import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.runtime.* import com.faraphel.tasks_valider.connectivity.bwd.BwdManager @@ -10,9 +11,7 @@ import com.faraphel.tasks_valider.connectivity.task.TaskClient import com.faraphel.tasks_valider.connectivity.task.session.TaskSession import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationClientScreen -import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role.CommunicationInternetClientContent import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController -import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget @@ -23,7 +22,7 @@ fun CommunicationWifiP2pClientScreen(activity: Activity, bwdManager: BwdManager) // if the client is not connected, show the connection screen if (client.value == null) - return CommunicationWifiP2pClientContent(client, bwdManager) + return CommunicationWifiP2pClientContent(activity, client, bwdManager) // if the user is not authenticated, show the authentication screen if (session.value == null) return AuthenticationClientScreen(activity, client.value!!, session) @@ -39,11 +38,13 @@ fun CommunicationWifiP2pClientScreen(activity: Activity, bwdManager: BwdManager) @Composable fun CommunicationWifiP2pClientContent( + activity: Activity, client: MutableState, bwdManager: BwdManager, ) { val selectedDevice = remember { mutableStateOf(null) } + // if the device is not selected if (selectedDevice.value == null) { Column { WifiP2pDeviceListWidget( @@ -66,11 +67,20 @@ fun CommunicationWifiP2pClientContent( } bwdManager.connect(config) { bwdManager.requestConnectionInfo { connectionInfo -> + // if the group has not been formed correctly, the host did not approve the connection + if (!connectionInfo.groupFormed) { + selectedDevice.value = null + Toast.makeText(activity, "Require host approval.", Toast.LENGTH_LONG).show() + return@requestConnectionInfo + } + + // create a connection to the server // TODO(Faraphel): check if the server is reachable client.value = TaskClient( - connectionInfo.groupOwnerAddress.toString(), + connectionInfo.groupOwnerAddress.hostAddress!!, DEFAULT_SERVER_PORT ) } } + } \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/widgets/connectivity/WifiP2pDeviceListWidget.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/widgets/connectivity/WifiP2pDeviceListWidget.kt index 9c09b82..9bf4826 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/widgets/connectivity/WifiP2pDeviceListWidget.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/widgets/connectivity/WifiP2pDeviceListWidget.kt @@ -2,10 +2,14 @@ package com.faraphel.tasks_valider.ui.widgets.connectivity import android.net.wifi.p2p.WifiP2pDevice import android.net.wifi.p2p.WifiP2pDeviceList -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp /** @@ -20,9 +24,24 @@ fun WifiP2pDeviceListWidget( filter: ((WifiP2pDevice) -> Boolean)? = null, deviceState: MutableState? = null, ) { - Text(text = "Devices (${peers?.deviceList?.size ?: 0})") + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // title + Text( + text = "Devices", + fontSize = 32.sp, + ) + // found device count + Text( + text = "(${peers?.deviceList?.size ?: 0})", + fontSize = 24.sp, + ) + + // separator + Spacer(modifier = Modifier.height(24.dp)) - Column { // if there are peers to display if (peers != null) { // for every device in the list From 5c2928597cbbbb90663f5c9247cb1dc6d689c1c5 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 30 Jun 2024 17:36:48 +0200 Subject: [PATCH 6/7] added more example data --- .../faraphel/tasks_valider/database/test.kt | 81 +++++++++++++++---- .../connection/internet/role/client.kt | 36 ++++++--- .../connection/wifiP2p/role/client.kt | 37 ++++++--- .../tasks_valider/ui/screen/task/student.kt | 5 +- 4 files changed, 116 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/faraphel/tasks_valider/database/test.kt b/app/src/main/java/com/faraphel/tasks_valider/database/test.kt index ff027fb..4e84074 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/database/test.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/database/test.kt @@ -74,46 +74,97 @@ fun populateTaskDatabaseTest(database: TaskDatabase) { taskA1Id, taskA2Id, taskA3Id, - taskB1Id, - taskB2Id, + taskA4Id, + taskA5Id, ) = database.taskDao().insert( + // Subject A TaskEntity( - title = "Commencer A", - description = "Description 1", + title = "Installation Debian", + description = "Installer la dernière version de Debian sur les Raspberry Pi.", order = 1, subjectId = subjectA.id, ), TaskEntity( - title = "Continuer A", - description = "Description 2", + title = "Connection de LEDs", + description = + "Utiliser les broches GPIO du Raspberry Pi pour brancher vos LEDs.\n" + + "N'oublier pas les résistances !", order = 2, - subjectId = subjectA.id + subjectId = subjectA.id, ), TaskEntity( - title = "Finir A", - description = "Description 3", + title = "IDLE Python", + description = "Installer l'éditeur basique Python avec 'apt install idle-python3.11'.", order = 3, - subjectId = subjectA.id + subjectId = subjectA.id, ), TaskEntity( - title = "Commencer B", - description = "Description 1", + title = "Clignotement de LEDs", + description = "Faite clignoter les différentes LEDs.", + order = 4, + subjectId = subjectA.id, + ), + TaskEntity( + title = "Feu Tricolore", + description = "Simuler un feu de circulation à l'aide de vos components.", + order = 5, + subjectId = subjectA.id, + ), + ) + + val ( + taskB1Id, + taskB2Id, + taskB3Id, + taskB4Id, + taskB5Id, + ) = database.taskDao().insert( + // Subject B + TaskEntity( + title = "Préparation Arduino", + description = "Préparer votre Arduino et assurer vous qu'il soit reconnu par votre ordinateur.", order = 1, subjectId = subjectB.id, ), TaskEntity( - title = "Finir B", - description = "Description 2", + title = "Connection de LEDs", + description = + "Utiliser les broches de votre Arduino pour brancher vos LEDs.\n" + + "N'oublier pas les résistances !", order = 2, subjectId = subjectB.id, - ) + ), + TaskEntity( + title = "IDE Arduino", + description = "Installer l'éditeur de code 'Arduino IDE'.", + order = 3, + subjectId = subjectB.id, + ), + TaskEntity( + title = "Clignotement de LEDs", + description = "Faite clignoter les différentes LEDs.", + order = 4, + subjectId = subjectB.id, + ), + TaskEntity( + title = "Feu Tricolore", + description = "Simuler un feu de circulation à l'aide de vos components.", + order = 5, + subjectId = subjectB.id, + ), ) val taskA1 = database.taskDao().getById(taskA1Id)!! val taskA2 = database.taskDao().getById(taskA2Id)!! val taskA3 = database.taskDao().getById(taskA3Id)!! + val taskA4 = database.taskDao().getById(taskA4Id)!! + val taskA5 = database.taskDao().getById(taskA5Id)!! + val taskB1 = database.taskDao().getById(taskB1Id)!! val taskB2 = database.taskDao().getById(taskB2Id)!! + val taskB3 = database.taskDao().getById(taskB3Id)!! + val taskB4 = database.taskDao().getById(taskB4Id)!! + val taskB5 = database.taskDao().getById(taskB5Id)!! } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt index 05b6565..3ec7087 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/internet/role/client.kt @@ -16,6 +16,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.task.TaskClient import com.faraphel.tasks_valider.connectivity.task.session.TaskSession import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationClientScreen @@ -27,22 +30,29 @@ import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController @Composable fun CommunicationInternetClientScreen(activity: Activity) { + val controller = rememberNavController() + val client = remember { mutableStateOf(null) } val session = remember { mutableStateOf(null) } - // if the client is not connected, show the connection screen - if (client.value == null) - return CommunicationInternetClientContent(client) - // if the user is not authenticated, show the authentication screen - if (session.value == null) - return AuthenticationClientScreen(activity, client.value!!, session) - - // show the main screen - TaskSessionController( - activity, - client.value!!, - session.value!!.person, - ) + NavHost(controller, startDestination = "communication") { + composable("communication") { + CommunicationInternetClientContent(client) + if (client.value != null) controller.navigate("authentication") + } + composable("authentication") { + AuthenticationClientScreen(activity, client.value!!, session) + if (session.value != null) controller.navigate("session") + } + composable("session") { + // show the main screen + TaskSessionController( + activity, + client.value!!, + session.value!!.person, + ) + } + } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt index a823f55..c9be389 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/connection/wifiP2p/role/client.kt @@ -6,33 +6,44 @@ import android.net.wifi.p2p.WifiP2pDevice import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.runtime.* +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.faraphel.tasks_valider.connectivity.bwd.BwdManager import com.faraphel.tasks_valider.connectivity.task.TaskClient import com.faraphel.tasks_valider.connectivity.task.session.TaskSession import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT import com.faraphel.tasks_valider.ui.screen.communication.authentication.AuthenticationClientScreen +import com.faraphel.tasks_valider.ui.screen.communication.connection.internet.role.CommunicationInternetClientContent import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget @Composable fun CommunicationWifiP2pClientScreen(activity: Activity, bwdManager: BwdManager) { + val controller = rememberNavController() + val client = remember { mutableStateOf(null) } val session = remember { mutableStateOf(null) } - // if the client is not connected, show the connection screen - if (client.value == null) - return CommunicationWifiP2pClientContent(activity, client, bwdManager) - // if the user is not authenticated, show the authentication screen - if (session.value == null) - return AuthenticationClientScreen(activity, client.value!!, session) - - // show the main screen - TaskSessionController( - activity, - client.value!!, - session.value!!.person, - ) + NavHost(controller, startDestination = "communication") { + composable("communication") { + CommunicationWifiP2pClientContent(activity, client, bwdManager) + if (client.value != null) controller.navigate("authentication") + } + composable("authentication") { + AuthenticationClientScreen(activity, client.value!!, session) + if (session.value != null) controller.navigate("session") + } + composable("session") { + // show the main screen + TaskSessionController( + activity, + client.value!!, + session.value!!.person, + ) + } + } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt index e14d086..bc9c657 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/task/student.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.faraphel.tasks_valider.connectivity.task.TaskClient @@ -43,7 +44,7 @@ fun TaskStudentScreen( client, student, tasks, - validations + validations, ) }.start() @@ -105,7 +106,7 @@ fun TaskStudentScreen( client, student, tasks, - validations + validations, ) }.start() } From ce3cf5fb1e4d395e0e8673071ece208f61335e79 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 30 Jun 2024 17:58:58 +0200 Subject: [PATCH 7/7] =?UTF-8?q?am=C3=A9lioration=20du=20fichier=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index eff70fe..b13bbfd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,22 @@ # Master 1 - Projet de Spécialité Ce projet consiste en une application Android permettant à des enseignants de créer des session de cours où un ensemble -d'élève est assigné à des tâches de sujet différent qui peuvent être validé collaborativement. +d'élève est assigné à des tâches qui peuvent être validées de manière collaborative. -Il est possible d'utiliser le QR code des cartes étudiantes afin de substituer l'identifiant d'un étudiant et de -pouvoir valider rapidement les tâches d'un élève. +Voici les fonctionnalités proposées : +- Connection entre plusieurs appareils en IP ou Wi-Fi Direct +- Création de session de cours contenant une classe et des enseignants +- Authentification à l'aide du QR code présent sur les cartes étudiantes +- Support de différents sujets composés de différentes questions pour chaqu'un des élèves +- Possibilité pour un enseignant de rejoindre la connection pour valider collaborativement les tâches des élèves +- Possibilité pour un étudiant de rejoindre la connection pour vérifier les tâches validées +- Exportation des données dans un fichier `JSON` +- Validation rapide permettant de valider la tâche suivante d'un élève à l'aide de son QR code # Build -1. Cloner le projet `git clone https://git.faraphel.fr/study-faraphel/M1-PDS` -2. Ouvrer le dans Android Studio ou Intellij IDEA \ No newline at end of file +1. Cloner le projet à l'aide de la commande `git clone https://git.faraphel.fr/study-faraphel/M1-PDS` +2. Ouvrer le dans [Android Studio](https://developer.android.com/studio?hl=fr) ou [Intellij IDEA](https://www.jetbrains.com/idea/) +3. Sélectionner votre téléphone dans le [menu de configuration] (https://www.jetbrains.com/help/idea/run-debug-configuration.html) + (l'utilisation d'émulateur n'est pas préconisé pour la fonctionnalité Wi-Fi Direct) +4. Démarrer l'application avec le bouton `Run`