[WIP] implemented better UI, implemented validating student tasks and fixed an issue in the HEAD, POST and DELETE methods of the REST api
This commit is contained in:
parent
7545e6aca9
commit
e73477b626
20 changed files with 733 additions and 248 deletions
|
@ -11,7 +11,7 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId = "com.faraphel.tasks_valider"
|
||||
minSdk = 24
|
||||
minSdk = 26
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
@ -52,8 +52,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.13.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.1")
|
||||
implementation("androidx.activity:activity-compose:1.9.0")
|
||||
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||
implementation("androidx.compose.ui:ui")
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<!-- SDK -->
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="24"
|
||||
android:minSdkVersion="26"
|
||||
tools:ignore="GradleOverrides" />
|
||||
|
||||
<!-- Permissions -->
|
||||
|
|
|
@ -5,6 +5,8 @@ import okhttp3.MediaType.Companion.toMediaType
|
|||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,7 +34,7 @@ class TaskClient(
|
|||
this.cookies.addAll(cookies)
|
||||
}
|
||||
}
|
||||
)
|
||||
).callTimeout(30.seconds)
|
||||
.build()
|
||||
|
||||
// TODO(Faraphel): automatically convert content to the correct type ?
|
||||
|
|
|
@ -1,14 +1,68 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.ClassEntity
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
class ClassApi(dao: BaseTaskDao<ClassEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<ClassEntity>(
|
||||
dao,
|
||||
object: TypeToken<ClassEntity>() {},
|
||||
session
|
||||
)
|
||||
class ClassApi(private val dao: BaseTaskDao<ClassEntity>, private val session: SessionEntity) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ClassEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ClassEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ClassEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,14 +1,68 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
class PersonApi(dao: BaseTaskDao<PersonEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<PersonEntity>(
|
||||
dao,
|
||||
object: TypeToken<PersonEntity>() {},
|
||||
session
|
||||
)
|
||||
class PersonApi(private val dao: BaseTaskDao<PersonEntity>, private val session: SessionEntity) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, PersonEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, PersonEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, PersonEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +1,72 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.RelationClassPersonEntity
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
|
||||
class RelationClassPersonApi(dao: BaseTaskDao<RelationClassPersonEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<RelationClassPersonEntity>(
|
||||
dao,
|
||||
object: TypeToken<RelationClassPersonEntity>() {},
|
||||
session
|
||||
)
|
||||
class RelationClassPersonApi(
|
||||
private val dao: BaseTaskDao<RelationClassPersonEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationClassPersonEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationClassPersonEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationClassPersonEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +1,72 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.RelationPersonSessionSubjectEntity
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
|
||||
class RelationPersonSessionSubjectApi(dao: BaseTaskDao<RelationPersonSessionSubjectEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<RelationPersonSessionSubjectEntity>(
|
||||
dao,
|
||||
object: TypeToken<RelationPersonSessionSubjectEntity>() {},
|
||||
session
|
||||
)
|
||||
class RelationPersonSessionSubjectApi(
|
||||
private val dao: BaseTaskDao<RelationPersonSessionSubjectEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationPersonSessionSubjectEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationPersonSessionSubjectEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, RelationPersonSessionSubjectEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,13 +1,71 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
class SessionApi(dao: BaseTaskDao<SessionEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<SessionEntity>(
|
||||
dao,
|
||||
object: TypeToken<SessionEntity>() {},
|
||||
session
|
||||
)
|
||||
|
||||
class SessionApi(
|
||||
private val dao: BaseTaskDao<SessionEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SessionEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SessionEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SessionEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +1,72 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.faraphel.tasks_valider.database.entities.SubjectEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
|
||||
class SubjectApi(dao: BaseTaskDao<SubjectEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<SubjectEntity>(
|
||||
dao,
|
||||
object: TypeToken<SubjectEntity>() {},
|
||||
session
|
||||
)
|
||||
class SubjectApi(
|
||||
private val dao: BaseTaskDao<SubjectEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SubjectEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SubjectEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, SubjectEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +1,72 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.faraphel.tasks_valider.database.entities.TaskEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
|
||||
class TaskApi(dao: BaseTaskDao<TaskEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<TaskEntity>(
|
||||
dao,
|
||||
object: TypeToken<TaskEntity>() {},
|
||||
session
|
||||
)
|
||||
class TaskApi(
|
||||
private val dao: BaseTaskDao<TaskEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, TaskEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, TaskEntity::class.java)
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, TaskEntity::class.java)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +1,74 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities
|
||||
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseTaskApi
|
||||
import com.faraphel.tasks_valider.database.api.entities.base.BaseApi
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.faraphel.tasks_valider.database.entities.ValidationEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.faraphel.tasks_valider.utils.getBody
|
||||
import com.google.gson.Gson
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
|
||||
class ValidationApi(dao: BaseTaskDao<ValidationEntity>, session: SessionEntity) :
|
||||
BaseTaskApi<ValidationEntity>(
|
||||
dao,
|
||||
object: TypeToken<ValidationEntity>() {},
|
||||
session
|
||||
)
|
||||
class ValidationApi(
|
||||
private val dao: BaseTaskDao<ValidationEntity>,
|
||||
private val session: SessionEntity
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ValidationEntity::class.java)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ValidationEntity::class.java)
|
||||
// save the data into the database
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
// get the content of the request
|
||||
val data = httpSession.getBody()
|
||||
// parse the object
|
||||
val obj = parser.fromJson(data, ValidationEntity::class.java)
|
||||
// delete the object from the database
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities.base
|
||||
|
||||
import android.util.Log
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseCronDao
|
||||
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
/**
|
||||
* A base for the API to handle the database operations.
|
||||
* This is preconfigured to handle JSON data.
|
||||
* @param Entity the entity type to handle
|
||||
*/
|
||||
abstract class BaseJsonApi<Entity: BaseEntity>(
|
||||
private val dao: BaseCronDao<Entity>,
|
||||
private val entityTypeToken: TypeToken<Entity>,
|
||||
) : BaseApi {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
val obj = parser.fromJson<Entity>(
|
||||
httpSession.inputStream.bufferedReader().readText(),
|
||||
this.entityTypeToken.type
|
||||
)
|
||||
val exists = this.dao.exists(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAll())
|
||||
)
|
||||
}
|
||||
|
||||
override fun post(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
val data = httpSession.inputStream.bufferedReader().readText()
|
||||
Log.i("post data", "data raw : $data")
|
||||
|
||||
val obj = parser.fromJson<Entity>(
|
||||
data,
|
||||
this.entityTypeToken.type
|
||||
)
|
||||
|
||||
Log.i("post data", "data parsed : $obj")
|
||||
|
||||
val id = this.dao.insert(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.CREATED,
|
||||
"text/plain",
|
||||
id.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun delete(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
val obj = parser.fromJson<Entity>(
|
||||
httpSession.inputStream.bufferedReader().readText(),
|
||||
this.entityTypeToken.type
|
||||
)
|
||||
val count = this.dao.delete(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (count > 0) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
count.toString()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package com.faraphel.tasks_valider.database.api.entities.base
|
||||
|
||||
import com.faraphel.tasks_valider.database.dao.base.BaseTaskDao
|
||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
|
||||
/**
|
||||
* A base for the API to handle the database operations.
|
||||
* This is preconfigured to handle data for Task objects.
|
||||
* @param Entity the entity type to handle
|
||||
*/
|
||||
abstract class BaseTaskApi<Entity: BaseEntity>(
|
||||
private val dao: BaseTaskDao<Entity>,
|
||||
private val entityTypeToken: TypeToken<Entity>,
|
||||
private val session: SessionEntity,
|
||||
) : BaseJsonApi<Entity>(
|
||||
dao,
|
||||
entityTypeToken,
|
||||
) {
|
||||
companion object {
|
||||
private val parser = Gson() ///< The JSON parser
|
||||
}
|
||||
|
||||
// Requests
|
||||
|
||||
override fun head(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
val obj = parser.fromJson<Entity>(
|
||||
httpSession.inputStream.bufferedReader().readText(),
|
||||
this.entityTypeToken.type
|
||||
)
|
||||
// check if the object is in the object accessible from the session
|
||||
val exists = this.dao.getAllBySession(session.id).contains(obj)
|
||||
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
if (exists) NanoHTTPD.Response.Status.OK else NanoHTTPD.Response.Status.NOT_FOUND,
|
||||
"text/plain",
|
||||
if (exists) "Exists" else "Not found"
|
||||
)
|
||||
}
|
||||
|
||||
override fun get(httpSession: NanoHTTPD.IHTTPSession): NanoHTTPD.Response {
|
||||
return NanoHTTPD.newFixedLengthResponse(
|
||||
NanoHTTPD.Response.Status.OK,
|
||||
"application/json",
|
||||
parser.toJson(this.dao.getAllBySession(session.id))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.faraphel.tasks_valider.ui.screen.authentification
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
|
@ -8,6 +8,10 @@ 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.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
|
||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||
|
||||
|
@ -20,19 +24,37 @@ fun AuthentificationServerScreen(personEntity: MutableState<PersonEntity?>) {
|
|||
val firstName = remember { mutableStateOf("") }
|
||||
val lastName = remember { mutableStateOf("") }
|
||||
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// title
|
||||
Text(
|
||||
text = "Your Profile",
|
||||
fontSize = 32.sp
|
||||
)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// first name
|
||||
TextField(
|
||||
value = firstName.value,
|
||||
placeholder = { Text("first name") },
|
||||
onValueChange = { text -> firstName.value = text },
|
||||
)
|
||||
|
||||
// last name
|
||||
TextField(
|
||||
value = lastName.value,
|
||||
placeholder = { Text("last name") },
|
||||
onValueChange = { text -> lastName.value = text },
|
||||
)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// confirm button
|
||||
Button(onClick = {
|
||||
// create the person entity with the given information
|
||||
|
|
|
@ -3,10 +3,14 @@ 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.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
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
|
||||
|
@ -29,7 +33,20 @@ fun CommunicationInternetSelectScreen(activity: Activity, database: TaskDatabase
|
|||
|
||||
@Composable
|
||||
fun CommunicationInternetSelectContent(controller: NavController) {
|
||||
Column {
|
||||
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
|
||||
|
|
|
@ -4,8 +4,7 @@ import android.app.Activity
|
|||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
|
@ -13,7 +12,14 @@ import androidx.compose.material3.DropdownMenuItem
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.TextMeasurer
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
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
|
||||
|
@ -93,43 +99,71 @@ fun CommunicationInternetServerContent(
|
|||
Thread { refreshClasses(database, classes) }.start()
|
||||
}
|
||||
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// title
|
||||
Text(
|
||||
text = "New Session",
|
||||
fontSize = 32.sp
|
||||
)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// classes
|
||||
Button(onClick = { areClassesExpanded.value = !areClassesExpanded.value }) {
|
||||
Row {
|
||||
Text(text = "Class")
|
||||
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)
|
||||
if (selectedClass.value != null) Text(text = selectedClass.value!!.name)
|
||||
else Text(text = "<Not selected>")
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
// descriptor
|
||||
Text(text = "Port")
|
||||
// separator
|
||||
Spacer(modifier = Modifier.width(width = 12.dp))
|
||||
// input
|
||||
TextField(
|
||||
modifier = Modifier.width(80.dp),
|
||||
value = serverPort.intValue.toString(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true,
|
||||
onValueChange = { text ->
|
||||
val port = text.toInt()
|
||||
if (port in RANGE_SERVER_PORT) {
|
||||
serverPort.intValue = port
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// check if a class is selected
|
||||
if (selectedClass.value != null)
|
||||
|
|
|
@ -4,12 +4,17 @@ import android.app.Activity
|
|||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
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
|
||||
|
@ -58,7 +63,20 @@ fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase)
|
|||
fun CommunicationSelectContent(controller: NavController, activity: Activity) {
|
||||
val isWifiP2pSupported = BwfManager.isSupported(activity)
|
||||
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// title
|
||||
Text(
|
||||
text = "Connection Type",
|
||||
fontSize = 32.sp
|
||||
)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// internet communication mode
|
||||
Button(onClick = { controller.navigate("internet") }) {
|
||||
Text("Internet")
|
||||
|
@ -68,7 +86,7 @@ fun CommunicationSelectContent(controller: NavController, activity: Activity) {
|
|||
Button(
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
// if the WiFi-Direct is not supported, the button is grayed out
|
||||
containerColor = if (isWifiP2pSupported) Color.Unspecified else Color.Gray
|
||||
containerColor = if (isWifiP2pSupported) MaterialTheme.colorScheme.primary else Color.Gray
|
||||
),
|
||||
onClick = {
|
||||
// if the WiFi-Direct is supported, navigate to the WiFi-Direct screen
|
||||
|
|
|
@ -4,13 +4,17 @@ import android.app.Activity
|
|||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
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.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||
import com.google.gson.Gson
|
||||
|
@ -44,10 +48,25 @@ fun TaskSessionScreen(
|
|||
selectedStudent.value!!
|
||||
)
|
||||
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// title
|
||||
Text(
|
||||
text = "Session",
|
||||
fontSize = 32.sp
|
||||
)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// if the groups have already been defined, display them
|
||||
for (student in students.value!!) {
|
||||
Button(onClick = { selectedStudent.value = student }) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp, horizontal = 16.dp),
|
||||
onClick = { selectedStudent.value = student },
|
||||
) {
|
||||
Text(text = student.fullName())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ import android.os.Build
|
|||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -14,6 +13,11 @@ 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.font.FontWeight
|
||||
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.TaskPermission
|
||||
import com.faraphel.tasks_valider.database.entities.*
|
||||
|
@ -25,7 +29,6 @@ import java.time.Instant
|
|||
* This screen represent a student
|
||||
* @param student the student object
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
@Composable
|
||||
fun TaskStudentScreen(
|
||||
activity: Activity,
|
||||
|
@ -47,8 +50,17 @@ fun TaskStudentScreen(
|
|||
)
|
||||
}.start()
|
||||
|
||||
Column {
|
||||
Text(text = student.fullName())
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// title
|
||||
Text(text = "Student", fontSize = 32.sp)
|
||||
// student name - subtitle
|
||||
Text(text = student.fullName(), fontSize = 24.sp)
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// if both the list of tasks and validations are loaded
|
||||
if (!(tasks.value == null || validations.value == null)) {
|
||||
|
@ -56,22 +68,31 @@ fun TaskStudentScreen(
|
|||
// get the validation
|
||||
val validation = validations.value!!.firstOrNull { validation -> validation.taskId == task.id }
|
||||
|
||||
Button(onClick = {}) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp, horizontal = 64.dp),
|
||||
) {
|
||||
Row {
|
||||
Column {
|
||||
// task title
|
||||
Text(task.title)
|
||||
Text(text = task.title, fontWeight = FontWeight.Bold)
|
||||
// task description
|
||||
task.description?.let { description -> Text(description) }
|
||||
// if the task have been validated, show the date
|
||||
if (validation != null) Text(validation.date.toString())
|
||||
}
|
||||
|
||||
// separator
|
||||
Spacer(modifier = Modifier.fillMaxWidth())
|
||||
|
||||
// the validation state
|
||||
Checkbox(
|
||||
checked = validation != null,
|
||||
enabled = user.role.permissions.contains(TaskPermission.WRITE),
|
||||
onCheckedChange = { state ->
|
||||
Thread {
|
||||
// TODO(Faraphel): simplify or put the UI refresh in the update function ?
|
||||
|
||||
// send a notification to the server about the validation
|
||||
updateValidation(
|
||||
client,
|
||||
state,
|
||||
|
@ -82,6 +103,14 @@ fun TaskStudentScreen(
|
|||
task.id,
|
||||
)
|
||||
)
|
||||
// refresh the UI
|
||||
refreshTasksValidations(
|
||||
activity,
|
||||
client,
|
||||
student,
|
||||
tasks,
|
||||
validations
|
||||
)
|
||||
}.start()
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.faraphel.tasks_valider.utils
|
||||
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
import java.nio.charset.Charset
|
||||
|
||||
|
||||
/**
|
||||
* Return the body of a request as a string.
|
||||
* :param charset: the encoding of the body
|
||||
*/
|
||||
fun NanoHTTPD.IHTTPSession.getBody(
|
||||
charset: Charset = Charset.forName("UTF-8")
|
||||
): String {
|
||||
// get the length of the body
|
||||
val length = this.headers["content-length"]!!.toInt()
|
||||
// prepare a buffer for the body
|
||||
val buffer = ByteArray(length)
|
||||
// read the body into the buffer
|
||||
this.inputStream.read(buffer, 0, length)
|
||||
// convert that buffer into a string
|
||||
return buffer.toString(charset)
|
||||
}
|
Loading…
Reference in a new issue