|
|
|
@ -5,32 +5,45 @@ import android.util.Log
|
|
|
|
|
import androidx.compose.foundation.background
|
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
|
import androidx.compose.foundation.layout.IntrinsicSize
|
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
|
|
import androidx.compose.foundation.layout.width
|
|
|
|
|
import androidx.compose.material.icons.Icons
|
|
|
|
|
import androidx.compose.material.icons.filled.ArrowBack
|
|
|
|
|
import androidx.compose.material3.Icon
|
|
|
|
|
import androidx.compose.material3.IconButton
|
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
|
import androidx.compose.runtime.MutableState
|
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
|
import androidx.compose.runtime.mutableIntStateOf
|
|
|
|
|
import androidx.compose.runtime.mutableStateMapOf
|
|
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
|
|
import androidx.compose.runtime.remember
|
|
|
|
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
|
|
|
import androidx.compose.runtime.setValue
|
|
|
|
|
import androidx.compose.ui.Alignment
|
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
|
import androidx.compose.ui.geometry.Offset
|
|
|
|
|
import androidx.compose.ui.geometry.Rect
|
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
|
import androidx.compose.ui.platform.LocalConfiguration
|
|
|
|
|
import androidx.compose.ui.res.painterResource
|
|
|
|
|
import androidx.compose.ui.zIndex
|
|
|
|
|
import arrow.core.Either
|
|
|
|
|
import com.iqball.app.R
|
|
|
|
|
import com.iqball.app.component.BasketCourt
|
|
|
|
|
import com.iqball.app.component.BasketCourtStates
|
|
|
|
|
import com.iqball.app.component.StepsTree
|
|
|
|
|
import com.iqball.app.model.TacticInfo
|
|
|
|
|
import com.iqball.app.model.tactic.ComponentId
|
|
|
|
|
import com.iqball.app.model.tactic.CourtType
|
|
|
|
|
import com.iqball.app.model.tactic.StepNodeInfo
|
|
|
|
|
import com.iqball.app.net.service.TacticService
|
|
|
|
|
import com.iqball.app.session.Token
|
|
|
|
|
import kotlinx.coroutines.runBlocking
|
|
|
|
|
import net.engawapg.lib.zoomable.rememberZoomState
|
|
|
|
|
import java.time.Instant
|
|
|
|
|
import java.time.LocalDateTime
|
|
|
|
|
import java.time.ZoneId
|
|
|
|
@ -47,6 +60,7 @@ fun VisualizerPage(
|
|
|
|
|
tacticId: Int,
|
|
|
|
|
) {
|
|
|
|
|
val dataEither = remember { initializeVisualizer(service, auth, tacticId) }
|
|
|
|
|
val showTree = remember { mutableStateOf(true) }
|
|
|
|
|
|
|
|
|
|
val (info, rootStep) = when (dataEither) {
|
|
|
|
|
// On error return a text to print it to the user
|
|
|
|
@ -58,13 +72,12 @@ fun VisualizerPage(
|
|
|
|
|
var selectedStepId by rememberSaveable { mutableIntStateOf(rootStep.id) }
|
|
|
|
|
val content = remember(selectedStepId) {
|
|
|
|
|
runBlocking {
|
|
|
|
|
val result = service.getTacticStepContent(auth, tacticId, selectedStepId)
|
|
|
|
|
.onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving root content: {}",
|
|
|
|
|
it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
val result = service.getTacticStepContent(auth, tacticId, selectedStepId).onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving root content: {}",
|
|
|
|
|
it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
when (result) {
|
|
|
|
|
is Either.Left -> throw Error("Unexpected error")
|
|
|
|
|
is Either.Right -> result.value
|
|
|
|
@ -72,21 +85,42 @@ fun VisualizerPage(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d("CONTENT", content.toString())
|
|
|
|
|
|
|
|
|
|
Column {
|
|
|
|
|
VisualizerHeader(title = info.name)
|
|
|
|
|
VisualizerHeader(title = info.name, showTree)
|
|
|
|
|
when (screenOrientation) {
|
|
|
|
|
Configuration.ORIENTATION_PORTRAIT -> StepsTree(
|
|
|
|
|
root = rootStep,
|
|
|
|
|
Configuration.ORIENTATION_PORTRAIT -> StepsTree(root = rootStep,
|
|
|
|
|
selectedNodeId = selectedStepId,
|
|
|
|
|
onNodeSelected = { selectedStepId = it.id }
|
|
|
|
|
)
|
|
|
|
|
onNodeSelected = { selectedStepId = it.id })
|
|
|
|
|
|
|
|
|
|
Configuration.ORIENTATION_LANDSCAPE -> {
|
|
|
|
|
val courtOffsets =
|
|
|
|
|
remember(showTree.value, content) { mutableStateMapOf<ComponentId, Offset>() }
|
|
|
|
|
val courtArea = remember(showTree.value) { mutableStateOf(Rect.Zero) }
|
|
|
|
|
val courtZoomState = rememberZoomState()
|
|
|
|
|
remember(showTree.value, content) {
|
|
|
|
|
runBlocking {
|
|
|
|
|
courtZoomState.reset()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Configuration.ORIENTATION_LANDSCAPE -> BasketCourt(
|
|
|
|
|
content = content,
|
|
|
|
|
type = info.type
|
|
|
|
|
)
|
|
|
|
|
val courtModifier =
|
|
|
|
|
if (showTree.value) Modifier.width(IntrinsicSize.Min) else Modifier.fillMaxWidth()
|
|
|
|
|
|
|
|
|
|
Row(modifier = Modifier.background(Color.LightGray)) {
|
|
|
|
|
BasketCourt(
|
|
|
|
|
content = content,
|
|
|
|
|
type = info.type,
|
|
|
|
|
modifier = courtModifier,
|
|
|
|
|
state = BasketCourtStates(courtOffsets, courtArea, courtZoomState)
|
|
|
|
|
)
|
|
|
|
|
if (showTree.value) {
|
|
|
|
|
StepsTree(root = rootStep,
|
|
|
|
|
selectedNodeId = selectedStepId,
|
|
|
|
|
onNodeSelected = { selectedStepId = it.id })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else -> throw Exception("Could not determine device's orientation.")
|
|
|
|
|
}
|
|
|
|
@ -95,17 +129,18 @@ fun VisualizerPage(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
private fun VisualizerHeader(title: String) {
|
|
|
|
|
private fun VisualizerHeader(title: String, showTree: MutableState<Boolean>) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.fillMaxWidth()
|
|
|
|
|
.zIndex(10000F)
|
|
|
|
|
.background(Color.White),
|
|
|
|
|
horizontalArrangement = Arrangement.SpaceBetween,
|
|
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
|
|
) {
|
|
|
|
|
IconButton(
|
|
|
|
|
onClick = { /*TODO*/ }
|
|
|
|
|
) {
|
|
|
|
|
IconButton(onClick = { /*TODO*/ }) {
|
|
|
|
|
Icon(
|
|
|
|
|
imageVector = Icons.Filled.ArrowBack,
|
|
|
|
|
contentDescription = "Back",
|
|
|
|
@ -115,44 +150,39 @@ private fun VisualizerHeader(title: String) {
|
|
|
|
|
|
|
|
|
|
Text(text = title, color = Color.Black)
|
|
|
|
|
|
|
|
|
|
Text(text = "")
|
|
|
|
|
IconButton(onClick = { showTree.value = !showTree.value }) {
|
|
|
|
|
Icon(
|
|
|
|
|
painter = painterResource(id = R.drawable.tree_icon),
|
|
|
|
|
contentDescription = "toggle show tree"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun initializeVisualizer(
|
|
|
|
|
service: TacticService,
|
|
|
|
|
auth: Token,
|
|
|
|
|
tacticId: Int
|
|
|
|
|
service: TacticService, auth: Token, tacticId: Int
|
|
|
|
|
): Either<String, VisualizerInitialData> {
|
|
|
|
|
val (tacticInfo, tacticTree) = runBlocking {
|
|
|
|
|
val tacticInfo = service.getTacticInfo(auth, tacticId)
|
|
|
|
|
.map {
|
|
|
|
|
TacticInfo(
|
|
|
|
|
id = it.id,
|
|
|
|
|
name = it.name,
|
|
|
|
|
type = CourtType.valueOf(
|
|
|
|
|
it.courtType.lowercase().replaceFirstChar(Char::uppercaseChar)
|
|
|
|
|
),
|
|
|
|
|
creationDate = LocalDateTime.ofInstant(
|
|
|
|
|
Instant.ofEpochMilli(it.creationDate),
|
|
|
|
|
ZoneId.systemDefault()
|
|
|
|
|
)
|
|
|
|
|
val tacticInfo = service.getTacticInfo(auth, tacticId).map {
|
|
|
|
|
TacticInfo(
|
|
|
|
|
id = it.id, name = it.name, type = CourtType.valueOf(
|
|
|
|
|
it.courtType.lowercase().replaceFirstChar(Char::uppercaseChar)
|
|
|
|
|
), creationDate = LocalDateTime.ofInstant(
|
|
|
|
|
Instant.ofEpochMilli(it.creationDate), ZoneId.systemDefault()
|
|
|
|
|
)
|
|
|
|
|
}.onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving tacticInfo : {}",
|
|
|
|
|
it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}.onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving tacticInfo : {}", it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val tacticTree = service.getTacticStepsTree(auth, tacticId)
|
|
|
|
|
.map { it.root }
|
|
|
|
|
.onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving tactic steps tree: {}",
|
|
|
|
|
it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
val tacticTree = service.getTacticStepsTree(auth, tacticId).map { it.root }.onLeft {
|
|
|
|
|
Log.e(
|
|
|
|
|
"received error response from server when retrieving tactic steps tree: {}",
|
|
|
|
|
it.toString()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pair(tacticInfo.getOrNull(), tacticTree.getOrNull())
|
|
|
|
|
}
|
|
|
|
|