[WIP] using JSON and HTTP server / client to communicate between the devices

This commit is contained in:
Faraphel 2024-05-05 14:24:05 +02:00
parent 2637f2fe8b
commit a604e01c12
22 changed files with 233 additions and 197 deletions

View file

@ -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>

View file

@ -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">

View file

@ -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")

View file

@ -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)

View file

@ -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()
}
}

View file

@ -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()

View file

@ -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())
}
}

View file

@ -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()
}
}

View file

@ -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") }
}
}

View file

@ -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)
}
}

View file

@ -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>?
}
} }

View file

@ -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")

View file

@ -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)
} }
} }
} }

View file

@ -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")
} }

View file

@ -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)
} }
} }
} }

View file

@ -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

View file

@ -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)
} }
} }
} }

View file

@ -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()
} }
}) { }) {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 {