[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 {
|
defaultConfig {
|
||||||
applicationId = "com.faraphel.tasks_valider"
|
applicationId = "com.faraphel.tasks_valider"
|
||||||
minSdk = 24
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
|
@ -52,8 +52,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.core:core-ktx:1.13.0")
|
implementation("androidx.core:core-ktx:1.13.1")
|
||||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.1")
|
||||||
implementation("androidx.activity:activity-compose:1.9.0")
|
implementation("androidx.activity:activity-compose:1.9.0")
|
||||||
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||||
implementation("androidx.compose.ui:ui")
|
implementation("androidx.compose.ui:ui")
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<!-- SDK -->
|
<!-- SDK -->
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="24"
|
android:minSdkVersion="26"
|
||||||
tools:ignore="GradleOverrides" />
|
tools:ignore="GradleOverrides" />
|
||||||
|
|
||||||
<!-- Permissions -->
|
<!-- Permissions -->
|
||||||
|
|
|
@ -5,6 +5,8 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +34,7 @@ class TaskClient(
|
||||||
this.cookies.addAll(cookies)
|
this.cookies.addAll(cookies)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
).callTimeout(30.seconds)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// TODO(Faraphel): automatically convert content to the correct type ?
|
// TODO(Faraphel): automatically convert content to the correct type ?
|
||||||
|
|
|
@ -1,14 +1,68 @@
|
||||||
package com.faraphel.tasks_valider.database.api.entities
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.ClassEntity
|
import com.faraphel.tasks_valider.database.entities.ClassEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
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) :
|
class ClassApi(private val dao: BaseTaskDao<ClassEntity>, private val session: SessionEntity) : BaseApi {
|
||||||
BaseTaskApi<ClassEntity>(
|
companion object {
|
||||||
dao,
|
private val parser = Gson() ///< The JSON parser
|
||||||
object: TypeToken<ClassEntity>() {},
|
}
|
||||||
session
|
|
||||||
|
// 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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
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) :
|
class PersonApi(private val dao: BaseTaskDao<PersonEntity>, private val session: SessionEntity) : BaseApi {
|
||||||
BaseTaskApi<PersonEntity>(
|
companion object {
|
||||||
dao,
|
private val parser = Gson() ///< The JSON parser
|
||||||
object: TypeToken<PersonEntity>() {},
|
}
|
||||||
session
|
|
||||||
|
// 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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.RelationClassPersonEntity
|
import com.faraphel.tasks_valider.database.entities.RelationClassPersonEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
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) :
|
class RelationClassPersonApi(
|
||||||
BaseTaskApi<RelationClassPersonEntity>(
|
private val dao: BaseTaskDao<RelationClassPersonEntity>,
|
||||||
dao,
|
private val session: SessionEntity
|
||||||
object: TypeToken<RelationClassPersonEntity>() {},
|
) : BaseApi {
|
||||||
session
|
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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.RelationPersonSessionSubjectEntity
|
import com.faraphel.tasks_valider.database.entities.RelationPersonSessionSubjectEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
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) :
|
class RelationPersonSessionSubjectApi(
|
||||||
BaseTaskApi<RelationPersonSessionSubjectEntity>(
|
private val dao: BaseTaskDao<RelationPersonSessionSubjectEntity>,
|
||||||
dao,
|
private val session: SessionEntity
|
||||||
object: TypeToken<RelationPersonSessionSubjectEntity>() {},
|
) : BaseApi {
|
||||||
session
|
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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
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>(
|
class SessionApi(
|
||||||
dao,
|
private val dao: BaseTaskDao<SessionEntity>,
|
||||||
object: TypeToken<SessionEntity>() {},
|
private val session: SessionEntity
|
||||||
session
|
) : 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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.SubjectEntity
|
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) :
|
class SubjectApi(
|
||||||
BaseTaskApi<SubjectEntity>(
|
private val dao: BaseTaskDao<SubjectEntity>,
|
||||||
dao,
|
private val session: SessionEntity
|
||||||
object: TypeToken<SubjectEntity>() {},
|
) : BaseApi {
|
||||||
session
|
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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.TaskEntity
|
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) :
|
class TaskApi(
|
||||||
BaseTaskApi<TaskEntity>(
|
private val dao: BaseTaskDao<TaskEntity>,
|
||||||
dao,
|
private val session: SessionEntity
|
||||||
object: TypeToken<TaskEntity>() {},
|
) : BaseApi {
|
||||||
session
|
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
|
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.dao.base.BaseTaskDao
|
||||||
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
import com.faraphel.tasks_valider.database.entities.SessionEntity
|
||||||
import com.faraphel.tasks_valider.database.entities.ValidationEntity
|
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) :
|
class ValidationApi(
|
||||||
BaseTaskApi<ValidationEntity>(
|
private val dao: BaseTaskDao<ValidationEntity>,
|
||||||
dao,
|
private val session: SessionEntity
|
||||||
object: TypeToken<ValidationEntity>() {},
|
) : BaseApi {
|
||||||
session
|
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
|
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.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
|
@ -8,6 +8,10 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
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.connectivity.task.session.TaskRole
|
||||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
|
|
||||||
|
@ -20,19 +24,37 @@ fun AuthentificationServerScreen(personEntity: MutableState<PersonEntity?>) {
|
||||||
val firstName = remember { mutableStateOf("") }
|
val firstName = remember { mutableStateOf("") }
|
||||||
val lastName = 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
|
// first name
|
||||||
TextField(
|
TextField(
|
||||||
value = firstName.value,
|
value = firstName.value,
|
||||||
|
placeholder = { Text("first name") },
|
||||||
onValueChange = { text -> firstName.value = text },
|
onValueChange = { text -> firstName.value = text },
|
||||||
)
|
)
|
||||||
|
|
||||||
// last name
|
// last name
|
||||||
TextField(
|
TextField(
|
||||||
value = lastName.value,
|
value = lastName.value,
|
||||||
|
placeholder = { Text("last name") },
|
||||||
onValueChange = { text -> lastName.value = text },
|
onValueChange = { text -> lastName.value = text },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// separator
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
// confirm button
|
// confirm button
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
// create the person entity with the given information
|
// 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.app.Activity
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
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.NavController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
|
@ -29,7 +33,20 @@ fun CommunicationInternetSelectScreen(activity: Activity, database: TaskDatabase
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetSelectContent(controller: NavController) {
|
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
|
// client mode
|
||||||
Button(onClick = { controller.navigate("client") }) { Text("Client") }
|
Button(onClick = { controller.navigate("client") }) { Text("Client") }
|
||||||
// server mode
|
// server mode
|
||||||
|
|
|
@ -4,8 +4,7 @@ import android.app.Activity
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
@ -13,7 +12,14 @@ import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.runtime.*
|
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.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.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
@ -93,16 +99,34 @@ fun CommunicationInternetServerContent(
|
||||||
Thread { refreshClasses(database, classes) }.start()
|
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
|
// 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 }) {
|
Button(onClick = { areClassesExpanded.value = !areClassesExpanded.value }) {
|
||||||
Row {
|
|
||||||
Text(text = "Class")
|
|
||||||
// display the selected class, if selected
|
// display the selected class, if selected
|
||||||
if (selectedClass.value != null)
|
if (selectedClass.value != null) Text(text = selectedClass.value!!.name)
|
||||||
Text(text = selectedClass.value!!.name)
|
else Text(text = "<Not selected>")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// class selector
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = areClassesExpanded.value,
|
expanded = areClassesExpanded.value,
|
||||||
onDismissRequest = { areClassesExpanded.value = false }
|
onDismissRequest = { areClassesExpanded.value = false }
|
||||||
|
@ -118,11 +142,20 @@ fun CommunicationInternetServerContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// server port
|
// server port
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
// descriptor
|
||||||
|
Text(text = "Port")
|
||||||
|
// separator
|
||||||
|
Spacer(modifier = Modifier.width(width = 12.dp))
|
||||||
|
// input
|
||||||
TextField(
|
TextField(
|
||||||
|
modifier = Modifier.width(80.dp),
|
||||||
value = serverPort.intValue.toString(),
|
value = serverPort.intValue.toString(),
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
singleLine = true,
|
||||||
onValueChange = { text ->
|
onValueChange = { text ->
|
||||||
val port = text.toInt()
|
val port = text.toInt()
|
||||||
if (port in RANGE_SERVER_PORT) {
|
if (port in RANGE_SERVER_PORT) {
|
||||||
|
@ -130,6 +163,7 @@ fun CommunicationInternetServerContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// check if a class is selected
|
// check if a class is selected
|
||||||
if (selectedClass.value != null)
|
if (selectedClass.value != null)
|
||||||
|
|
|
@ -4,12 +4,17 @@ import android.app.Activity
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
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.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
|
@ -58,7 +63,20 @@ fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase)
|
||||||
fun CommunicationSelectContent(controller: NavController, activity: Activity) {
|
fun CommunicationSelectContent(controller: NavController, activity: Activity) {
|
||||||
val isWifiP2pSupported = BwfManager.isSupported(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
|
// internet communication mode
|
||||||
Button(onClick = { controller.navigate("internet") }) {
|
Button(onClick = { controller.navigate("internet") }) {
|
||||||
Text("Internet")
|
Text("Internet")
|
||||||
|
@ -68,7 +86,7 @@ fun CommunicationSelectContent(controller: NavController, activity: Activity) {
|
||||||
Button(
|
Button(
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
// if the WiFi-Direct is not supported, the button is grayed out
|
// 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 = {
|
onClick = {
|
||||||
// if the WiFi-Direct is supported, navigate to the WiFi-Direct screen
|
// 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.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
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.connectivity.task.TaskClient
|
||||||
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
@ -44,10 +48,25 @@ fun TaskSessionScreen(
|
||||||
selectedStudent.value!!
|
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
|
// if the groups have already been defined, display them
|
||||||
for (student in students.value!!) {
|
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())
|
Text(text = student.fullName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
@ -14,6 +13,11 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
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.TaskClient
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission
|
||||||
import com.faraphel.tasks_valider.database.entities.*
|
import com.faraphel.tasks_valider.database.entities.*
|
||||||
|
@ -25,7 +29,6 @@ import java.time.Instant
|
||||||
* This screen represent a student
|
* This screen represent a student
|
||||||
* @param student the student object
|
* @param student the student object
|
||||||
*/
|
*/
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TaskStudentScreen(
|
fun TaskStudentScreen(
|
||||||
activity: Activity,
|
activity: Activity,
|
||||||
|
@ -47,8 +50,17 @@ fun TaskStudentScreen(
|
||||||
)
|
)
|
||||||
}.start()
|
}.start()
|
||||||
|
|
||||||
Column {
|
Column(
|
||||||
Text(text = student.fullName())
|
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 both the list of tasks and validations are loaded
|
||||||
if (!(tasks.value == null || validations.value == null)) {
|
if (!(tasks.value == null || validations.value == null)) {
|
||||||
|
@ -56,22 +68,31 @@ fun TaskStudentScreen(
|
||||||
// get the validation
|
// get the validation
|
||||||
val validation = validations.value!!.firstOrNull { validation -> validation.taskId == task.id }
|
val validation = validations.value!!.firstOrNull { validation -> validation.taskId == task.id }
|
||||||
|
|
||||||
Button(onClick = {}) {
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp, horizontal = 64.dp),
|
||||||
|
) {
|
||||||
Row {
|
Row {
|
||||||
Column {
|
Column {
|
||||||
// task title
|
// task title
|
||||||
Text(task.title)
|
Text(text = task.title, fontWeight = FontWeight.Bold)
|
||||||
// task description
|
// task description
|
||||||
task.description?.let { description -> Text(description) }
|
task.description?.let { description -> Text(description) }
|
||||||
// if the task have been validated, show the date
|
// if the task have been validated, show the date
|
||||||
if (validation != null) Text(validation.date.toString())
|
if (validation != null) Text(validation.date.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// separator
|
||||||
|
Spacer(modifier = Modifier.fillMaxWidth())
|
||||||
|
|
||||||
// the validation state
|
// the validation state
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = validation != null,
|
checked = validation != null,
|
||||||
enabled = user.role.permissions.contains(TaskPermission.WRITE),
|
enabled = user.role.permissions.contains(TaskPermission.WRITE),
|
||||||
onCheckedChange = { state ->
|
onCheckedChange = { state ->
|
||||||
Thread {
|
Thread {
|
||||||
|
// TODO(Faraphel): simplify or put the UI refresh in the update function ?
|
||||||
|
|
||||||
|
// send a notification to the server about the validation
|
||||||
updateValidation(
|
updateValidation(
|
||||||
client,
|
client,
|
||||||
state,
|
state,
|
||||||
|
@ -82,6 +103,14 @@ fun TaskStudentScreen(
|
||||||
task.id,
|
task.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
// refresh the UI
|
||||||
|
refreshTasksValidations(
|
||||||
|
activity,
|
||||||
|
client,
|
||||||
|
student,
|
||||||
|
tasks,
|
||||||
|
validations
|
||||||
|
)
|
||||||
}.start()
|
}.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