[WIP] using JSON and HTTP server / client to communicate between the devices
This commit is contained in:
parent
2637f2fe8b
commit
a604e01c12
22 changed files with 233 additions and 197 deletions
|
@ -4,34 +4,36 @@
|
||||||
<value>
|
<value>
|
||||||
<entry key="app">
|
<entry key="app">
|
||||||
<State>
|
<State>
|
||||||
<targetSelectedWithDropDown>
|
<runningDeviceTargetSelectedWithDropDown>
|
||||||
<Target>
|
<Target>
|
||||||
<type value="QUICK_BOOT_TARGET" />
|
<type value="RUNNING_DEVICE_TARGET" />
|
||||||
<deviceKey>
|
<deviceKey>
|
||||||
<Key>
|
<Key>
|
||||||
<type value="VIRTUAL_DEVICE_PATH" />
|
<type value="SERIAL_NUMBER" />
|
||||||
<value value="C:\Users\RC606\.android\avd\Small_Phone_API_26.avd" />
|
<value value="2XJDU17923000406" />
|
||||||
</Key>
|
</Key>
|
||||||
</deviceKey>
|
</deviceKey>
|
||||||
</Target>
|
</Target>
|
||||||
</targetSelectedWithDropDown>
|
</runningDeviceTargetSelectedWithDropDown>
|
||||||
<timeTargetWasSelectedWithDropDown value="2024-05-04T10:43:32.941497Z" />
|
<timeTargetWasSelectedWithDropDown value="2024-05-05T12:21:32.176293Z" />
|
||||||
|
<runningDeviceTargetsSelectedWithDialog>
|
||||||
|
<Target>
|
||||||
|
<type value="RUNNING_DEVICE_TARGET" />
|
||||||
|
<deviceKey>
|
||||||
|
<Key>
|
||||||
|
<type value="VIRTUAL_DEVICE_PATH" />
|
||||||
|
<value value="C:\Users\RC606\.android\avd\Small_Phone_API_34.avd" />
|
||||||
|
</Key>
|
||||||
|
</deviceKey>
|
||||||
|
</Target>
|
||||||
|
</runningDeviceTargetsSelectedWithDialog>
|
||||||
<targetsSelectedWithDialog>
|
<targetsSelectedWithDialog>
|
||||||
<Target>
|
<Target>
|
||||||
<type value="QUICK_BOOT_TARGET" />
|
<type value="QUICK_BOOT_TARGET" />
|
||||||
<deviceKey>
|
<deviceKey>
|
||||||
<Key>
|
<Key>
|
||||||
<type value="VIRTUAL_DEVICE_PATH" />
|
<type value="VIRTUAL_DEVICE_PATH" />
|
||||||
<value value="C:\Users\RC606\.android\avd\Small_Phone_API_26.avd" />
|
<value value="C:\Users\RC606\.android\avd\Small_Phone_API_34_-_2.avd" />
|
||||||
</Key>
|
|
||||||
</deviceKey>
|
|
||||||
</Target>
|
|
||||||
<Target>
|
|
||||||
<type value="QUICK_BOOT_TARGET" />
|
|
||||||
<deviceKey>
|
|
||||||
<Key>
|
|
||||||
<type value="VIRTUAL_DEVICE_PATH" />
|
|
||||||
<value value="C:\Users\RC606\.android\avd\Small_Phone_API_26_-_2.avd" />
|
|
||||||
</Key>
|
</Key>
|
||||||
</deviceKey>
|
</deviceKey>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
|
|
|
@ -63,6 +63,9 @@ dependencies {
|
||||||
implementation("androidx.room:room-ktx:2.6.1")
|
implementation("androidx.room:room-ktx:2.6.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||||
implementation("androidx.navigation:navigation-compose:2.7.7")
|
implementation("androidx.navigation:navigation-compose:2.7.7")
|
||||||
|
implementation("org.nanohttpd:nanohttpd:2.3.1")
|
||||||
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
|
implementation("com.squareup.okhttp3:okhttp-android:5.0.0-alpha.14")
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
|
|
@ -7,7 +7,7 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.database.Database
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.CommunicationScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.CommunicationScreen
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class MainActivity : ComponentActivity() {
|
||||||
private var bwfManager: BwfManager? = null ///< the WiFi-Direct helper
|
private var bwfManager: BwfManager? = null ///< the WiFi-Direct helper
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private lateinit var database: Database ///< the database manager
|
private lateinit var database: TaskDatabase ///< the database manager
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.packets
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base for a packet that can be encoded and decoded for a Socket
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
sealed class BasePacket {
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Create a new instance from an array of bytes.
|
|
||||||
* @param data: data obtained from the toBytes function.
|
|
||||||
*/
|
|
||||||
inline fun <reified Packet: BasePacket> fromBytes(data: ByteArray): Packet {
|
|
||||||
return Json.decodeFromString<Packet>(data.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the content of the packet into an array of bytes
|
|
||||||
*/
|
|
||||||
fun toBytes(): ByteArray {
|
|
||||||
return Json.encodeToString(this).encodeToByteArray()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.packets
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a simple packet class to test a connection
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
data object PacketPing : BasePacket()
|
|
|
@ -1,43 +0,0 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.room
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import com.faraphel.tasks_valider.connectivity.packets.BasePacket
|
|
||||||
import com.faraphel.tasks_valider.connectivity.packets.PacketPing
|
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.InetSocketAddress
|
|
||||||
import java.net.Socket
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A client to handle the room connection.
|
|
||||||
* @param address the address of the server
|
|
||||||
* @param port the port of the server
|
|
||||||
*/
|
|
||||||
class RoomClient(
|
|
||||||
private val address: InetAddress,
|
|
||||||
private val port: Int
|
|
||||||
) : Thread() {
|
|
||||||
private val server = Socket()
|
|
||||||
|
|
||||||
constructor(address: String, port: Int) : this(InetAddress.getByName(address), port)
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
Log.d("room-client", "connecting to the server...")
|
|
||||||
try {
|
|
||||||
server.connect(InetSocketAddress(address, port), 10_000)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e("room-client", "could not connect to the server", exception)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Log.d("room-client", "connection successful !")
|
|
||||||
|
|
||||||
val serverIn = server.getInputStream()
|
|
||||||
val serverOut = server.getOutputStream()
|
|
||||||
|
|
||||||
serverOut.write(PacketPing.toBytes())
|
|
||||||
val data = serverIn.readBytes()
|
|
||||||
val packet = BasePacket.fromBytes<PacketPing>(data)
|
|
||||||
|
|
||||||
Log.d("room-client", packet.toString())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.room
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import com.faraphel.tasks_valider.connectivity.packets.PacketPing
|
|
||||||
import java.net.ServerSocket
|
|
||||||
import java.net.Socket
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A server to handle the room connection.
|
|
||||||
* @param port the port of the server
|
|
||||||
* @param timeout the timeout for a client (in milliseconds)
|
|
||||||
*/
|
|
||||||
class RoomServer(
|
|
||||||
private val port: Int,
|
|
||||||
private val timeout: Int = 10_000
|
|
||||||
) : Thread() {
|
|
||||||
private var server = ServerSocket(port)
|
|
||||||
|
|
||||||
init {
|
|
||||||
server.soTimeout = 0 // accepting clients take an infinite timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept and treat a client
|
|
||||||
*/
|
|
||||||
private fun handleClient(client: Socket) {
|
|
||||||
// TODO(Faraphel): should every client be handled in a new small thread ?
|
|
||||||
// Create the thread here and handle it until the connection is broken
|
|
||||||
|
|
||||||
val clientIn = client.getInputStream()
|
|
||||||
val clientOut = client.getOutputStream()
|
|
||||||
|
|
||||||
Log.i("room-server", "data: ${PacketPing.toBytes().toList()}")
|
|
||||||
clientOut.write(PacketPing.toBytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept connections and treat them
|
|
||||||
*/
|
|
||||||
override fun run() {
|
|
||||||
while (!server.isClosed) {
|
|
||||||
val client = server.accept()
|
|
||||||
client.soTimeout = timeout // set the timeout for the communication
|
|
||||||
this.handleClient(client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the server
|
|
||||||
*/
|
|
||||||
fun close() {
|
|
||||||
server.close()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.faraphel.tasks_valider.connectivity.task
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client to handle the room connection.
|
||||||
|
* @param address the address of the server
|
||||||
|
* @param port the port of the server
|
||||||
|
*/
|
||||||
|
class TaskClient(
|
||||||
|
private val address: InetAddress,
|
||||||
|
private val port: Int
|
||||||
|
) : Thread() {
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
private val jsonParser = Gson()
|
||||||
|
|
||||||
|
constructor(address: String, port: Int) : this(InetAddress.getByName(address), port)
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
Log.i("room-client", "started !")
|
||||||
|
|
||||||
|
// send a request to the server
|
||||||
|
val request = okhttp3.Request.Builder()
|
||||||
|
.url(URL("http://${address.hostAddress}:$port"))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// get the response
|
||||||
|
val response = client.newCall(request).execute()
|
||||||
|
|
||||||
|
// check if the response is successful
|
||||||
|
if (!response.isSuccessful) {
|
||||||
|
Log.e("room-client", "could not connect to the server")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.i("room-client", "connected to the server")
|
||||||
|
|
||||||
|
// parse the response
|
||||||
|
val body = response.body.string()
|
||||||
|
val data = jsonParser.fromJson(body, Map::class.java)
|
||||||
|
|
||||||
|
// print the data
|
||||||
|
data.forEach { (key, value) -> Log.d("room-client", "$key: $value") }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.faraphel.tasks_valider.connectivity.task
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
|
import com.faraphel.tasks_valider.database.entities.Task
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import fi.iki.elonen.NanoHTTPD
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A server to handle the task API to allow clients to interact with the database.
|
||||||
|
* @param port the port of the server
|
||||||
|
* @param database the database to interact with
|
||||||
|
*/
|
||||||
|
class TaskServer(
|
||||||
|
private val port: Int,
|
||||||
|
private val database: TaskDatabase
|
||||||
|
) : NanoHTTPD(port) {
|
||||||
|
private val jsonParser = Gson()
|
||||||
|
|
||||||
|
override fun serve(session: IHTTPSession): Response {
|
||||||
|
val method: Method = session.method
|
||||||
|
val uri: String = session.uri
|
||||||
|
|
||||||
|
// remove the first slash
|
||||||
|
val daoName: String = uri.substring(1)
|
||||||
|
|
||||||
|
// handle the request
|
||||||
|
when (method) {
|
||||||
|
// get the data from the database
|
||||||
|
Method.GET -> {
|
||||||
|
return newFixedLengthResponse(
|
||||||
|
Response.Status.OK,
|
||||||
|
"application/json",
|
||||||
|
jsonParser.toJson( database.taskDao().getAll() )
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// insert the data into the database
|
||||||
|
Method.POST -> {
|
||||||
|
val task = jsonParser.fromJson(
|
||||||
|
session.inputStream.bufferedReader(),
|
||||||
|
Task::class.java
|
||||||
|
)
|
||||||
|
database.taskDao().insert(task)
|
||||||
|
|
||||||
|
return newFixedLengthResponse(
|
||||||
|
Response.Status.CREATED,
|
||||||
|
"application/json",
|
||||||
|
jsonParser.toJson(task)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// other methods are not allowed
|
||||||
|
else -> {
|
||||||
|
return newFixedLengthResponse(
|
||||||
|
Response.Status.METHOD_NOT_ALLOWED,
|
||||||
|
"text/plain",
|
||||||
|
"Method not allowed"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// TODO(Faraphel): implement a permission system
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server with the default configuration
|
||||||
|
*/
|
||||||
|
override fun start() {
|
||||||
|
super.start(SOCKET_READ_TIMEOUT, false)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
package com.faraphel.tasks_valider.database
|
package com.faraphel.tasks_valider.database
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.DatabaseConfiguration
|
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
import com.faraphel.tasks_valider.database.converters.InstantConverter
|
import com.faraphel.tasks_valider.database.converters.InstantConverter
|
||||||
|
@ -13,15 +10,19 @@ import com.faraphel.tasks_valider.database.dao.StudentDao
|
||||||
import com.faraphel.tasks_valider.database.dao.TaskDao
|
import com.faraphel.tasks_valider.database.dao.TaskDao
|
||||||
import com.faraphel.tasks_valider.database.dao.TaskGroupDao
|
import com.faraphel.tasks_valider.database.dao.TaskGroupDao
|
||||||
import com.faraphel.tasks_valider.database.dao.TeacherDao
|
import com.faraphel.tasks_valider.database.dao.TeacherDao
|
||||||
|
import com.faraphel.tasks_valider.database.dao.base.BaseDao
|
||||||
import com.faraphel.tasks_valider.database.entities.Group
|
import com.faraphel.tasks_valider.database.entities.Group
|
||||||
import com.faraphel.tasks_valider.database.entities.GroupStudent
|
import com.faraphel.tasks_valider.database.entities.GroupStudent
|
||||||
import com.faraphel.tasks_valider.database.entities.Student
|
import com.faraphel.tasks_valider.database.entities.Student
|
||||||
import com.faraphel.tasks_valider.database.entities.Task
|
import com.faraphel.tasks_valider.database.entities.Task
|
||||||
import com.faraphel.tasks_valider.database.entities.TaskGroup
|
import com.faraphel.tasks_valider.database.entities.TaskGroup
|
||||||
import com.faraphel.tasks_valider.database.entities.Teacher
|
import com.faraphel.tasks_valider.database.entities.Teacher
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database for the tasks application.
|
||||||
|
* Contains the entities and the relations between them.
|
||||||
|
*/
|
||||||
@Database(
|
@Database(
|
||||||
entities = [
|
entities = [
|
||||||
Group::class,
|
Group::class,
|
||||||
|
@ -37,7 +38,7 @@ import java.time.Instant
|
||||||
@TypeConverters(
|
@TypeConverters(
|
||||||
InstantConverter::class
|
InstantConverter::class
|
||||||
)
|
)
|
||||||
abstract class Database : RoomDatabase() {
|
abstract class TaskDatabase : RoomDatabase() {
|
||||||
// entities
|
// entities
|
||||||
abstract fun groupDao(): GroupDao
|
abstract fun groupDao(): GroupDao
|
||||||
abstract fun studentDao(): StudentDao
|
abstract fun studentDao(): StudentDao
|
||||||
|
@ -47,4 +48,20 @@ abstract class Database : RoomDatabase() {
|
||||||
// relations
|
// relations
|
||||||
abstract fun groupStudentDao(): GroupStudentDao
|
abstract fun groupStudentDao(): GroupStudentDao
|
||||||
abstract fun taskGroupDao(): TaskGroupDao
|
abstract fun taskGroupDao(): TaskGroupDao
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the DAO from the name of the dao.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <Entity> daoFromName(name: String): BaseDao<Entity>? {
|
||||||
|
return when (name) {
|
||||||
|
"group" -> groupDao()
|
||||||
|
"student" -> studentDao()
|
||||||
|
"teacher" -> teacherDao()
|
||||||
|
"task" -> taskDao()
|
||||||
|
"group_student" -> groupStudentDao()
|
||||||
|
"task_group" -> taskGroupDao()
|
||||||
|
else -> null
|
||||||
|
} as BaseDao<Entity>?
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,16 +11,16 @@ import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import com.faraphel.tasks_valider.connectivity.room.RoomClient
|
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS
|
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskGroupScreen
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetClientScreen() {
|
fun CommunicationInternetClientScreen() {
|
||||||
val client = remember { mutableStateOf<RoomClient?>(null) }
|
val client = remember { mutableStateOf<TaskClient?>(null) }
|
||||||
|
|
||||||
if (client.value == null) CommunicationInternetClientContent(client)
|
if (client.value == null) CommunicationInternetClientContent(client)
|
||||||
else TaskGroupScreen()
|
else TaskGroupScreen()
|
||||||
|
@ -28,7 +28,7 @@ fun CommunicationInternetClientScreen() {
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetClientContent(client: MutableState<RoomClient?>) {
|
fun CommunicationInternetClientContent(client: MutableState<TaskClient?>) {
|
||||||
val serverAddress = remember { mutableStateOf(DEFAULT_SERVER_ADDRESS) }
|
val serverAddress = remember { mutableStateOf(DEFAULT_SERVER_ADDRESS) }
|
||||||
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ fun CommunicationInternetClientContent(client: MutableState<RoomClient?>) {
|
||||||
|
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
// TODO(Faraphel): check if the server is reachable
|
// TODO(Faraphel): check if the server is reachable
|
||||||
client.value = RoomClient(serverAddress.value, serverPort.intValue)
|
client.value = TaskClient(serverAddress.value, serverPort.intValue)
|
||||||
client.value!!.start()
|
client.value!!.start()
|
||||||
}) {
|
}) {
|
||||||
Text("Connect")
|
Text("Connect")
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package com.faraphel.tasks_valider.ui.screen.communication.internet
|
package com.faraphel.tasks_valider.ui.screen.communication.internet
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
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.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.activity
|
||||||
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
|
||||||
|
@ -13,7 +15,7 @@ import com.faraphel.tasks_valider.ui.screen.communication.internet.server.Commun
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetScreen() {
|
fun CommunicationInternetScreen(activity: Activity) {
|
||||||
val controller = rememberNavController()
|
val controller = rememberNavController()
|
||||||
|
|
||||||
NavHost(navController = controller, startDestination = "mode") {
|
NavHost(navController = controller, startDestination = "mode") {
|
||||||
|
@ -24,7 +26,7 @@ fun CommunicationInternetScreen() {
|
||||||
CommunicationInternetClientScreen()
|
CommunicationInternetClientScreen()
|
||||||
}
|
}
|
||||||
composable("server") {
|
composable("server") {
|
||||||
CommunicationInternetServerScreen()
|
CommunicationInternetServerScreen(activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.faraphel.tasks_valider.ui.screen.communication.internet.server
|
package com.faraphel.tasks_valider.ui.screen.communication.internet.server
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
@ -13,26 +15,27 @@ import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import androidx.room.Room
|
||||||
import com.faraphel.tasks_valider.connectivity.room.RoomServer
|
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
||||||
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskGroupScreen
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetServerScreen() {
|
fun CommunicationInternetServerScreen(activity: Activity) {
|
||||||
val server = remember { mutableStateOf<RoomServer?>(null)}
|
val server = remember { mutableStateOf<TaskServer?>(null)}
|
||||||
|
|
||||||
// if the server is not created, prompt the user for the server configuration
|
// if the server is not created, prompt the user for the server configuration
|
||||||
if (server.value == null) CommunicationInternetServerContent(server)
|
if (server.value == null) CommunicationInternetServerContent(activity, server)
|
||||||
// else, go to the base tasks screen
|
// else, go to the base tasks screen
|
||||||
else TaskGroupScreen()
|
else TaskGroupScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetServerContent(server: MutableState<RoomServer?>) {
|
fun CommunicationInternetServerContent(activity: Activity, server: MutableState<TaskServer?>) {
|
||||||
val expandedStudentList = remember { mutableStateOf(false) }
|
val expandedStudentList = remember { mutableStateOf(false) }
|
||||||
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
||||||
|
|
||||||
|
@ -69,9 +72,20 @@ fun CommunicationInternetServerContent(server: MutableState<RoomServer?>) {
|
||||||
)
|
)
|
||||||
|
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
server.value = RoomServer(serverPort.intValue)
|
// Reset the database | TODO(Faraphel): only for testing purpose
|
||||||
|
activity.deleteDatabase("local")
|
||||||
|
|
||||||
|
// Create the database
|
||||||
|
val database = Room.databaseBuilder(
|
||||||
|
activity,
|
||||||
|
TaskDatabase::class.java,
|
||||||
|
"local"
|
||||||
|
).build()
|
||||||
|
|
||||||
|
// Create the server
|
||||||
|
Log.i("room-server", "creating the server")
|
||||||
|
server.value = TaskServer(serverPort.intValue, database)
|
||||||
server.value!!.start()
|
server.value!!.start()
|
||||||
// TODO(Faraphel): go to the base tasks screen
|
|
||||||
}) {
|
}) {
|
||||||
Text("Create")
|
Text("Create")
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,11 @@ fun CommunicationScreen(activity: Activity) {
|
||||||
CommunicationSelectContent(controller, activity)
|
CommunicationSelectContent(controller, activity)
|
||||||
}
|
}
|
||||||
composable("internet") {
|
composable("internet") {
|
||||||
CommunicationInternetScreen()
|
CommunicationInternetScreen(activity)
|
||||||
}
|
}
|
||||||
composable("wifi-p2p") {
|
composable("wifi-p2p") {
|
||||||
val bwfManager = BwfManager.fromActivity(activity)
|
val bwfManager = BwfManager.fromActivity(activity)
|
||||||
CommunicationWifiP2pScreen(bwfManager)
|
CommunicationWifiP2pScreen(activity, bwfManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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 com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskGroupScreen
|
||||||
import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget
|
import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ fun CommunicationWifiP2pClientScreen(bwfManager: BwfManager) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if the device is selected but not connected, try to connect
|
// if the device is selected but not connected, try to connect
|
||||||
if (selectedDevice.value != null) {
|
if (selectedDevice.value != null) {
|
||||||
// TODO(Faraphel): error handling
|
// TODO(Faraphel): error handling
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p
|
package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
@ -9,14 +10,12 @@ 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
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.internet.CommunicationInternetScreen
|
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.internet.server.CommunicationInternetServerScreen
|
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.client.CommunicationWifiP2pClientScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.client.CommunicationWifiP2pClientScreen
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server.CommunicationWifiP2pServerScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server.CommunicationWifiP2pServerScreen
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationWifiP2pScreen(bwfManager: BwfManager) {
|
fun CommunicationWifiP2pScreen(activity: Activity, bwfManager: BwfManager) {
|
||||||
val controller = rememberNavController()
|
val controller = rememberNavController()
|
||||||
|
|
||||||
NavHost(navController = controller, startDestination = "mode") {
|
NavHost(navController = controller, startDestination = "mode") {
|
||||||
|
@ -27,7 +26,7 @@ fun CommunicationWifiP2pScreen(bwfManager: BwfManager) {
|
||||||
CommunicationWifiP2pClientScreen(bwfManager)
|
CommunicationWifiP2pClientScreen(bwfManager)
|
||||||
}
|
}
|
||||||
composable("server") {
|
composable("server") {
|
||||||
CommunicationWifiP2pServerScreen(bwfManager)
|
CommunicationWifiP2pServerScreen(activity, bwfManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server
|
package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
@ -13,19 +14,21 @@ import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.room.Room
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.connectivity.room.RoomServer
|
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
||||||
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskGroupScreen
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationWifiP2pServerScreen(bwfManager: BwfManager) {
|
fun CommunicationWifiP2pServerScreen(activity: Activity, bwfManager: BwfManager) {
|
||||||
val server = remember { mutableStateOf<RoomServer?>(null)}
|
val server = remember { mutableStateOf<TaskServer?>(null)}
|
||||||
|
|
||||||
// if the server is not created, prompt the user for the server configuration
|
// if the server is not created, prompt the user for the server configuration
|
||||||
if (server.value == null) CommunicationWifiP2pServerContent(bwfManager, server)
|
if (server.value == null) CommunicationWifiP2pServerContent(activity, bwfManager, server)
|
||||||
// else, go to the base tasks screen
|
// else, go to the base tasks screen
|
||||||
else TaskGroupScreen()
|
else TaskGroupScreen()
|
||||||
}
|
}
|
||||||
|
@ -33,8 +36,9 @@ fun CommunicationWifiP2pServerScreen(bwfManager: BwfManager) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationWifiP2pServerContent(
|
fun CommunicationWifiP2pServerContent(
|
||||||
|
activity: Activity,
|
||||||
bwfManager: BwfManager,
|
bwfManager: BwfManager,
|
||||||
server: MutableState<RoomServer?>
|
server: MutableState<TaskServer?>
|
||||||
) {
|
) {
|
||||||
val expandedStudentList = remember { mutableStateOf(false) }
|
val expandedStudentList = remember { mutableStateOf(false) }
|
||||||
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
||||||
|
@ -72,8 +76,21 @@ fun CommunicationWifiP2pServerContent(
|
||||||
)
|
)
|
||||||
|
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
|
// TODO(Faraphel): should be merged with the internet server
|
||||||
|
|
||||||
|
// Reset the database | TODO(Faraphel): only for testing purpose
|
||||||
|
activity.deleteDatabase("local")
|
||||||
|
|
||||||
|
// Create the database
|
||||||
|
val database = Room.databaseBuilder(
|
||||||
|
activity,
|
||||||
|
TaskDatabase::class.java,
|
||||||
|
"local"
|
||||||
|
).build()
|
||||||
|
|
||||||
bwfManager.recreateGroup {
|
bwfManager.recreateGroup {
|
||||||
server.value = RoomServer(serverPort.intValue)
|
// Create the server
|
||||||
|
server.value = TaskServer(serverPort.intValue, database)
|
||||||
server.value!!.start()
|
server.value!!.start()
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.faraphel.tasks_valider.ui.screen.tasks
|
package com.faraphel.tasks_valider.ui.screen.task
|
||||||
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
|
@ -1,4 +1,4 @@
|
||||||
package com.faraphel.tasks_valider.ui.widgets.tasks
|
package com.faraphel.tasks_valider.ui.widgets.task
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
|
@ -1,4 +1,4 @@
|
||||||
package com.faraphel.tasks_valider.ui.widgets.tasks
|
package com.faraphel.tasks_valider.ui.widgets.task
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
|
@ -1,4 +1,4 @@
|
||||||
package com.faraphel.tasks_valider.ui.widgets.tasks
|
package com.faraphel.tasks_valider.ui.widgets.task
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
@ -11,12 +11,12 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.faraphel.tasks_valider.database.Database
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.database.entities.TaskGroup
|
import com.faraphel.tasks_valider.database.entities.TaskGroup
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WidgetTaskStudent(database: Database, taskStudent: TaskGroup) {
|
fun WidgetTaskStudent(database: TaskDatabase, taskStudent: TaskGroup) {
|
||||||
val teacherDao = database.teacherDao()
|
val teacherDao = database.teacherDao()
|
||||||
|
|
||||||
Column {
|
Column {
|
Loading…
Reference in a new issue