diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index 5cd0755..da69b70 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -10,12 +10,32 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index f9d6e36..266c22b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,7 @@
-
+
diff --git a/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt b/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt
index b3ef37d..ef25ff9 100644
--- a/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt
+++ b/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt
@@ -1,20 +1,14 @@
package com.faraphel.tasks_valider
-import android.Manifest
import android.annotation.SuppressLint
-import android.content.Context
-import android.content.pm.PackageManager
-import android.net.wifi.p2p.WifiP2pManager
import android.os.Build
import android.os.Bundle
-import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
-import com.faraphel.tasks_valider.connectivity.bwf.error.BwfNotSupportedException
import com.faraphel.tasks_valider.database.Database
-import com.faraphel.tasks_valider.ui.screen.room.RoomScreen
+import com.faraphel.tasks_valider.ui.screen.communication.CommunicationScreen
class MainActivity : ComponentActivity() {
@@ -28,41 +22,8 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- // TODO(Faraphel): more check on permissions
-
- // check if the system support WiFi-Direct
- if (!this.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
- Log.e("wifi-p2p", "this device does not support the WiFi-Direct feature")
- throw BwfNotSupportedException()
- }
-
- if (
- this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
- this.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED
- ) {
- // TODO(Faraphel): should be used with shouldShowRequestPermissionRationale, with a check
- this.requestPermissions(
- arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
- BwfManager.PERMISSION_ACCESS_FINE_LOCATION
- )
- }
-
- // get the WiFi-Direct manager
- val manager = this.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
- if (manager == null) {
- Log.e("wifi-p2p", "cannot access the WiFi-Direct manager")
- throw BwfNotSupportedException()
- }
-
- // create a channel for the manager
- val channel = manager.initialize(this, this.mainLooper, null)
-
- // create a new manager for handling the WiFi-Direct
- this.bwfManager = BwfManager(manager, channel)
-
- // open the room selection screen
this.setContent {
- RoomScreen(this.bwfManager!!)
+ CommunicationScreen(this)
}
}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt
index 19780b3..31f6681 100644
--- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt
+++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt
@@ -1,10 +1,14 @@
package com.faraphel.tasks_valider.connectivity.bwf
+import android.Manifest
+import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager
import android.net.wifi.p2p.*
+import android.util.Log
import androidx.compose.runtime.mutableStateOf
import com.faraphel.tasks_valider.connectivity.bwf.error.*
@@ -28,6 +32,44 @@ class BwfManager(
addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
}
+
+ fun isSupported(context: Context): Boolean {
+ return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)
+ }
+
+ /**
+ * Create a new BwfManager from an activity.
+ * @param activity The activity to create the manager from
+ */
+ fun fromActivity(activity: Activity): BwfManager {
+ // check if the system support WiFi-Direct
+ if (this.isSupported(activity)) {
+ Log.e("wifi-p2p", "this device does not support the WiFi-Direct feature")
+ throw BwfNotSupportedException()
+ }
+
+ // TODO(Faraphel): more check on permissions
+ if (
+ activity.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
+ activity.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED
+ ) {
+ // TODO(Faraphel): should be used with shouldShowRequestPermissionRationale, with a check
+ activity.requestPermissions(
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ PERMISSION_ACCESS_FINE_LOCATION
+ )
+ }
+
+ // get the WiFi-Direct manager
+ val manager = activity.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
+ ?: throw BwfPermissionException()
+
+ // get the WiFi-Direct channel
+ val channel = manager.initialize(activity, activity.mainLooper, null)
+ return BwfManager(manager, channel)
+
+ // NOTE(Faraphel): the broadcast receiver should be registered in the activity onResume
+ }
}
// Wrappers
@@ -109,8 +151,7 @@ class BwfManager(
*
* Note: most of the failure on removal are caused by not having a group already created, which is checked.
*
- * @param listener: the createGroup listener
- * @param onRemoveFailure: error handler for the removeGroup event
+ * @param callback: the createGroup listener
*
* @see WifiP2pManager.createGroup
* @see WifiP2pManager.removeGroup
diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt
index 9f11424..3585496 100644
--- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt
+++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt
@@ -1,4 +1,4 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfNotSupportedException :
- BwfException("WiFi-Direct is not supported on this device, or it is disabled.")
\ No newline at end of file
+ BwfException("WiFi-Direct is not supported on this device.")
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfPermissionException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfPermissionException.kt
new file mode 100644
index 0000000..81c85ee
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfPermissionException.kt
@@ -0,0 +1,4 @@
+package com.faraphel.tasks_valider.connectivity.bwf.error
+
+class BwfPermissionException :
+ BwfException("WiFi-Direct requires permissions to work properly. Please grant the permissions.")
diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomClient.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomClient.kt
index 3431bbe..c902fe1 100644
--- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomClient.kt
+++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomClient.kt
@@ -16,10 +16,12 @@ import java.net.Socket
class RoomClient(
private val address: InetAddress,
private val port: Int
-) {
+) : Thread() {
private val server = Socket()
- fun start() {
+ 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)
diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomServer.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomServer.kt
index 4e51489..fee1c3e 100644
--- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomServer.kt
+++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/room/RoomServer.kt
@@ -14,7 +14,7 @@ import java.net.Socket
class RoomServer(
private val port: Int,
private val timeout: Int = 10_000
-) {
+) : Thread() {
private var server = ServerSocket(port)
init {
@@ -38,13 +38,18 @@ class RoomServer(
/**
* Accept connections and treat them
*/
- fun start() {
- Thread {
- while (true) {
- val client = server.accept()
- client.soTimeout = timeout // set the timeout for the communication
- this.handleClient(client)
- }
- }.start()
+ 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()
}
}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client/screen.kt
new file mode 100644
index 0000000..93a5769
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/client/screen.kt
@@ -0,0 +1,64 @@
+package com.faraphel.tasks_valider.ui.screen.communication.internet.client
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.text.input.KeyboardType
+import com.faraphel.tasks_valider.connectivity.room.RoomClient
+import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS
+import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
+import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
+import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
+
+
+@Composable
+fun CommunicationInternetClientScreen() {
+ val client = remember { mutableStateOf(null) }
+
+ if (client.value == null) CommunicationInternetClientContent(client)
+ else TaskGroupScreen()
+}
+
+
+@Composable
+fun CommunicationInternetClientContent(client: MutableState) {
+ val serverAddress = remember { mutableStateOf(DEFAULT_SERVER_ADDRESS) }
+ val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
+
+ Column {
+ // server address
+ TextField(
+ value = serverAddress.value,
+ onValueChange = { text ->
+ serverAddress.value = text
+ }
+ )
+
+ // server port
+ TextField(
+ value = serverPort.intValue.toString(),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+ onValueChange = { text ->
+ val port = text.toInt()
+ if (port in RANGE_SERVER_PORT) {
+ serverPort.intValue = port
+ }
+ }
+ )
+
+ Button(onClick = {
+ // TODO(Faraphel): check if the server is reachable
+ client.value = RoomClient(serverAddress.value, serverPort.intValue)
+ client.value!!.start()
+ }) {
+ Text("Connect")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/screen.kt
new file mode 100644
index 0000000..5b6995f
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/screen.kt
@@ -0,0 +1,45 @@
+package com.faraphel.tasks_valider.ui.screen.communication.internet
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import com.faraphel.tasks_valider.ui.screen.communication.internet.client.CommunicationInternetClientScreen
+import com.faraphel.tasks_valider.ui.screen.communication.internet.server.CommunicationInternetServerScreen
+
+
+@Composable
+fun CommunicationInternetScreen() {
+ val controller = rememberNavController()
+
+ NavHost(navController = controller, startDestination = "mode") {
+ composable("mode") {
+ CommunicationInternetSelectContent(controller)
+ }
+ composable("client") {
+ CommunicationInternetClientScreen()
+ }
+ composable("server") {
+ CommunicationInternetServerScreen()
+ }
+ }
+}
+
+
+@Composable
+fun CommunicationInternetSelectContent(controller: NavController) {
+ Column {
+ // client mode
+ Button(onClick = { controller.navigate("client") }) {
+ Text("Client")
+ }
+ // server mode
+ Button(onClick = { controller.navigate("server") }) {
+ Text("Server")
+ }
+ }
+}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server/screen.kt
new file mode 100644
index 0000000..478b71f
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/internet/server/screen.kt
@@ -0,0 +1,79 @@
+package com.faraphel.tasks_valider.ui.screen.communication.internet.server
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Button
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.text.input.KeyboardType
+import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
+import com.faraphel.tasks_valider.connectivity.room.RoomServer
+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.tasks.TaskGroupScreen
+
+
+@Composable
+fun CommunicationInternetServerScreen() {
+ val server = remember { mutableStateOf(null)}
+
+ // if the server is not created, prompt the user for the server configuration
+ if (server.value == null) CommunicationInternetServerContent(server)
+ // else, go to the base tasks screen
+ else TaskGroupScreen()
+}
+
+
+@Composable
+fun CommunicationInternetServerContent(server: MutableState) {
+ val expandedStudentList = remember { mutableStateOf(false) }
+ val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
+
+ Column {
+ // student list
+ Button(onClick = { expandedStudentList.value = !expandedStudentList.value }) {
+ Text(text = "Select Students List")
+ }
+ DropdownMenu(
+ expanded = expandedStudentList.value,
+ onDismissRequest = { expandedStudentList.value = false }
+ ) {
+ DropdownMenuItem(
+ text = { Text("ISRI") },
+ onClick = {}
+ )
+ DropdownMenuItem(
+ text = { Text("MIAGE") },
+ onClick = {}
+ )
+ // TODO(Faraphel): student lists should be loaded from the database or a file
+ }
+
+ // server port
+ TextField(
+ value = serverPort.intValue.toString(),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+ onValueChange = { text ->
+ val port = text.toInt()
+ if (port in RANGE_SERVER_PORT) {
+ serverPort.intValue = port
+ }
+ }
+ )
+
+ Button(onClick = {
+ server.value = RoomServer(serverPort.intValue)
+ server.value!!.start()
+ // TODO(Faraphel): go to the base tasks screen
+ }) {
+ Text("Create")
+ }
+ }
+}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/screen.kt
new file mode 100644
index 0000000..1a92119
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/screen.kt
@@ -0,0 +1,77 @@
+package com.faraphel.tasks_valider.ui.screen.communication
+
+import android.app.Activity
+import android.widget.Toast
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.navigation.NavController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
+import com.faraphel.tasks_valider.ui.screen.communication.internet.CommunicationInternetScreen
+import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationWifiP2pScreen
+
+
+/**
+ * CommunicationController is the main controller for the communication screen.
+ * It is responsible for handling the navigation between the different communication methods.
+ * It is also responsible for initializing the communication methods.
+ * @param activity: The activity that hosts the communication screen.
+ */
+@Composable
+fun CommunicationScreen(activity: Activity) {
+ val controller = rememberNavController()
+
+ NavHost(
+ navController = controller,
+ startDestination = "select"
+ ) {
+ composable("select") {
+ CommunicationSelectContent(controller, activity)
+ }
+ composable("internet") {
+ CommunicationInternetScreen()
+ }
+ composable("wifi-p2p") {
+ val bwfManager = BwfManager.fromActivity(activity)
+ CommunicationWifiP2pScreen(bwfManager)
+ }
+ }
+}
+
+
+/**
+ * Communication screen that allows the user to choose the communication mode
+ */
+@Composable
+fun CommunicationSelectContent(controller: NavController, activity: Activity) {
+ val isWifiP2pSupported = BwfManager.isSupported(activity)
+
+ Column {
+ // internet communication mode
+ Button(onClick = { controller.navigate("internet") }) {
+ Text("Internet")
+ }
+
+ // wifi-direct communication mode
+ Button(
+ colors = ButtonDefaults.buttonColors(
+ // if the WiFi-Direct is not supported, the button is grayed out
+ containerColor = if (isWifiP2pSupported) Color.Unspecified else Color.Gray
+ ),
+ onClick = {
+ // if the WiFi-Direct is supported, navigate to the WiFi-Direct screen
+ if (isWifiP2pSupported) controller.navigate("wifi-p2p")
+ // if the WiFi-Direct is not supported, show a toast message
+ else Toast.makeText(activity, "WiFi-Direct is not supported on this device", Toast.LENGTH_SHORT).show()
+ }
+ ) {
+ Text("WiFi-Direct")
+ }
+ }
+}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/settings.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/settings.kt
new file mode 100644
index 0000000..e9362dc
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/settings.kt
@@ -0,0 +1,6 @@
+package com.faraphel.tasks_valider.ui.screen.communication
+
+
+const val DEFAULT_SERVER_ADDRESS: String = "127.0.0.1"
+const val DEFAULT_SERVER_PORT: Int = 9876
+val RANGE_SERVER_PORT: IntRange = 1024..65535
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt
new file mode 100644
index 0000000..9e9e310
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/client/screen.kt
@@ -0,0 +1,55 @@
+package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.client
+
+import android.net.wifi.p2p.WifiP2pConfig
+import android.net.wifi.p2p.WifiP2pDevice
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
+import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
+import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget
+
+
+@Composable
+fun CommunicationWifiP2pClientScreen(bwfManager: BwfManager) {
+ val selectedDevice = remember { mutableStateOf(null) }
+ val isConnected = remember { mutableStateOf(false) }
+
+ // if connected, show the task group screen
+ if (isConnected.value) {
+ TaskGroupScreen()
+ return
+ }
+
+ // if the device is selected but not connected, try to connect
+ if (selectedDevice.value != null) {
+ // TODO(Faraphel): error handling
+ val config = WifiP2pConfig().apply {
+ deviceAddress = selectedDevice.value!!.deviceAddress
+ }
+ bwfManager.connect(config) {
+ isConnected.value = true
+ }
+ return
+ }
+
+ // display the list of devices
+ CommunicationWifiP2pClientContent(bwfManager, selectedDevice)
+}
+
+
+@Composable
+fun CommunicationWifiP2pClientContent(
+ bwfManager: BwfManager,
+ selectedDevice: MutableState
+) {
+ Column {
+ WifiP2pDeviceListWidget(
+ peers = bwfManager.statePeers.value,
+ filter = { device: WifiP2pDevice -> device.isGroupOwner },
+ selectedDevice,
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt
new file mode 100644
index 0000000..d9ea6a7
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/screen.kt
@@ -0,0 +1,48 @@
+package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import com.faraphel.tasks_valider.connectivity.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.server.CommunicationWifiP2pServerScreen
+
+
+@Composable
+fun CommunicationWifiP2pScreen(bwfManager: BwfManager) {
+ val controller = rememberNavController()
+
+ NavHost(navController = controller, startDestination = "mode") {
+ composable("mode") {
+ CommunicationWifiP2pSelectContent(controller)
+ }
+ composable("client") {
+ CommunicationWifiP2pClientScreen(bwfManager)
+ }
+ composable("server") {
+ CommunicationWifiP2pServerScreen(bwfManager)
+ }
+ }
+}
+
+
+@Composable
+fun CommunicationWifiP2pSelectContent(controller: NavController) {
+ Column {
+ // client mode
+ Button(onClick = { controller.navigate("client") }) {
+ Text("Client")
+ }
+ // server mode
+ Button(onClick = { controller.navigate("server") }) {
+ Text("Server")
+ }
+ }
+}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt
new file mode 100644
index 0000000..eadecdd
--- /dev/null
+++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/communication/wifiP2p/server/screen.kt
@@ -0,0 +1,83 @@
+package com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.server
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Button
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.text.input.KeyboardType
+import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
+import com.faraphel.tasks_valider.connectivity.room.RoomServer
+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.tasks.TaskGroupScreen
+
+
+@Composable
+fun CommunicationWifiP2pServerScreen(bwfManager: BwfManager) {
+ val server = remember { mutableStateOf(null)}
+
+ // if the server is not created, prompt the user for the server configuration
+ if (server.value == null) CommunicationWifiP2pServerContent(bwfManager, server)
+ // else, go to the base tasks screen
+ else TaskGroupScreen()
+}
+
+
+@Composable
+fun CommunicationWifiP2pServerContent(
+ bwfManager: BwfManager,
+ server: MutableState
+) {
+ val expandedStudentList = remember { mutableStateOf(false) }
+ val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
+
+ Column {
+ // student list
+ Button(onClick = { expandedStudentList.value = !expandedStudentList.value }) {
+ Text(text = "Select Students List")
+ }
+ DropdownMenu(
+ expanded = expandedStudentList.value,
+ onDismissRequest = { expandedStudentList.value = false }
+ ) {
+ DropdownMenuItem(
+ text = { Text("ISRI") },
+ onClick = {}
+ )
+ DropdownMenuItem(
+ text = { Text("MIAGE") },
+ onClick = {}
+ )
+ // TODO(Faraphel): student lists should be loaded from the database or a file
+ }
+
+ // server port
+ TextField(
+ value = serverPort.intValue.toString(),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+ onValueChange = { text ->
+ val port = text.toInt()
+ if (port in RANGE_SERVER_PORT) {
+ serverPort.intValue = port
+ }
+ }
+ )
+
+ Button(onClick = {
+ bwfManager.recreateGroup {
+ server.value = RoomServer(serverPort.intValue)
+ server.value!!.start()
+ }
+ }) {
+ Text("Create")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt
deleted file mode 100644
index 44b1b0b..0000000
--- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.faraphel.tasks_valider.ui.screen.room
-
-import android.net.wifi.p2p.WifiP2pConfig
-import android.net.wifi.p2p.WifiP2pDevice
-import android.net.wifi.p2p.WifiP2pDeviceList
-import android.util.Log
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.rememberNavController
-import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
-import com.faraphel.tasks_valider.connectivity.room.RoomClient
-import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
-import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget
-import kotlinx.coroutines.runBlocking
-
-
-/**
- * This screen allow the user to join a room
- */
-@Composable
-fun RoomClientScreen(bwfManager: BwfManager) {
- val navController = rememberNavController()
-
- val selectedDevice = remember { mutableStateOf(null) }
- val connected = remember { mutableStateOf(false) }
-
- NavHost(navController = navController, startDestination = "roomSearch") {
- composable(route = "roomSearch") {
- // let the user pick which host he wishes to connect to
- Column {
- Text(text = "Find a Server")
- // display all the devices that are owner of their group
- WifiP2pDeviceListWidget(
- peers = bwfManager.statePeers.value,
- filter = { device: WifiP2pDevice -> device.isGroupOwner },
- selectedDevice,
- )
- }
-
- // update the list when a new device is detected
- }
- composable(route = "taskGroup") {
- TaskGroupScreen()
- }
- }
-
- // if a device is selected, connect to it
- if (selectedDevice.value != null) {
- // configure the connection to point to the selected device
- val config = WifiP2pConfig().apply {
- deviceAddress = selectedDevice.value!!.deviceAddress
- }
-
- // try to connect to the host
- bwfManager.connect(config) {
- Log.i("room", "Connection successful to the host !")
-
- bwfManager.requestConnectionInfo { connectionInfo ->
- val client = RoomClient(connectionInfo.groupOwnerAddress, 9876) // TODO(Faraphel): port should be a settings
- Thread { client.start() }.start()
-
- connected.value = true
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt
deleted file mode 100644
index bb9ba87..0000000
--- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.faraphel.tasks_valider.ui.screen.room
-
-import android.util.Log
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material3.*
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.input.KeyboardType
-import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
-import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
-import kotlinx.coroutines.runBlocking
-import java.net.ServerSocket
-
-
-var DEFAULT_SERVER_PORT: Int = 9876
-
-
-/**
- * This screen allow the user to create a room
- */
-@Composable
-fun RoomHostScreen(bwfManager: BwfManager) {
- val expanded = remember { mutableStateOf(false) }
- val serverPort = remember { mutableStateOf(DEFAULT_SERVER_PORT) }
- val isCreated = remember { mutableStateOf(false) }
-
- // if the group have been created, display the group screen
- if (isCreated.value) {
- TaskGroupScreen()
- return
- }
-
- // ask the user settings about the room
- Column {
- Box(Modifier.fillMaxWidth()) {
- // dropdown button
- Button(onClick = { expanded.value = !expanded.value }) {
- Text(text = "Select Students List")
- }
- // dropdown list
- DropdownMenu(
- expanded = expanded.value,
- onDismissRequest = { expanded.value = false }
- ) {
- DropdownMenuItem(
- text = { Text("ISRI") },
- onClick = {}
- )
- DropdownMenuItem(
- text = { Text("MIAGE") },
- onClick = {}
- )
- }
- }
-
- // ask the user what will be the server port
- TextField(
- value = serverPort.value.toString(),
- keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
- onValueChange = { value -> serverPort.value = value.toIntOrNull() ?: DEFAULT_SERVER_PORT }
- )
-
- Button(onClick = {
- // create a new WiFi-Direct group
- bwfManager.recreateGroup {
- Log.i("room", "group created !")
-
- // open a new server
- val server = ServerSocket(serverPort.value)
- Thread {
- val client = server.accept() // TODO(Faraphel): should run in a thread
- client.getInputStream()
- }
-
- // mark the group as created
- isCreated.value = true
- }
- }) {
- Text("Create")
- }
- }
-
-}
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt
deleted file mode 100644
index efa95bd..0000000
--- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.faraphel.tasks_valider.ui.screen.room
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.rememberNavController
-import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
-
-
-/**
- * This screen will allow the user to choose which room is he connecting to, or let him create one.
- */
-@Composable
-fun RoomScreen(bwfManager: BwfManager) {
- val navController = rememberNavController()
-
- NavHost(navController = navController, startDestination = "pickMode") {
- composable(route = "pickMode") {
- Column {
- Button(onClick = { navController.navigate("client") }) {
- Text(text = "Join a room")
- }
- Button(onClick = { navController.navigate("host") }) {
- Text(text = "Create a room")
- }
- }
- }
- composable(route = "client") {
- RoomClientScreen(bwfManager)
- }
- composable(route = "host") {
- RoomHostScreen(bwfManager)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/tasks/TaskGroupScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/tasks/screen.kt
similarity index 100%
rename from app/src/main/java/com/faraphel/tasks_valider/ui/screen/tasks/TaskGroupScreen.kt
rename to app/src/main/java/com/faraphel/tasks_valider/ui/screen/tasks/screen.kt