Skip to content

Commit

Permalink
Added exporting competition and task to JSON and importing them back …
Browse files Browse the repository at this point in the history
…from JSON
  • Loading branch information
0awawa0 committed Jul 1, 2021
1 parent 0609e75 commit dbf2db6
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 30 deletions.
7 changes: 0 additions & 7 deletions src/main/kotlin/database/Models.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,3 @@ data class SolveModel(
val task: TaskModel,
val timestamp: Long
)

@Serializable
data class ScoreModel(
val competition: CompetitionModel,
val player: PlayerModel,
val score: Int
)
91 changes: 77 additions & 14 deletions src/main/kotlin/ui/competitions/CompetitionsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import javafx.stage.FileChooser
import tornadofx.*
import ui.BaseView
import ui.Colors
import java.io.File

class CompetitionsView: BaseView<CompetitionsViewModel>(CompetitionsViewModel(), "Competitions") {

Expand All @@ -39,25 +40,55 @@ class CompetitionsView: BaseView<CompetitionsViewModel>(CompetitionsViewModel(),
add(competitionsList)
competitionsList.fitToParentSize()

hbox {
vbox {
padding = Insets(8.0)
alignment = Pos.CENTER
spacing = 8.0
alignment = Pos.CENTER
hbox {
alignment = Pos.CENTER
spacing = 8.0

button {
text = "Add"

action { showNewCompetitionDialog() }
}.fitToParentWidth()
button {
text = "Delete"

action {
val competition = competitionsList.selectedItem ?: return@action
showAcceptCompetitionDeletionDialog(competition)
}
}.fitToParentWidth()
}.fitToParentWidth()

button {
text = "Add"
text = "Add from JSON"

action {
val file = chooseFile(
"Choose file",
arrayOf(FileChooser.ExtensionFilter("JSON", "*.json"))
).firstOrNull() ?: return@action
viewModel.addCompetitionsFromJson(file) { showFailedToParseJsonError() }
}
}.fitToParentWidth()

action { showNewCompetitionDialog() }
}
button {
text = "Delete"
text = "Export to JSON"

action {
val competition = competitionsList.selectedItem ?: return@action
showAcceptCompetitionDeletionDialog(competition)
val dir = chooseDirectory("Choose directory") ?: return@action
competition.exportToJson(
"${dir.absolutePath}/${competition.name}.json",
onSuccessAction = ::showExtractionSuccessfulMessage,
onErrorAction = ::showFailedToExportToJsonError
)
}
}
}.fitToParentWidth()
}.fitToParentWidth()
}
}

private val tasksTable = tableview<CompetitionsViewModel.TaskItem> {
Expand Down Expand Up @@ -110,7 +141,21 @@ class CompetitionsView: BaseView<CompetitionsViewModel>(CompetitionsViewModel(),
"Choose file",
arrayOf(FileChooser.ExtensionFilter("JSON", "*.json"))
).firstOrNull() ?: return@action
competition.addTasksFromJson(file) { showFailedToParseJson() }
competition.addTasksFromJson(file) { showFailedToParseJsonError() }
}
}

button {
text = "Export to JSON"

action {
val task = tasksTable.selectedItem ?: return@action
val dir = chooseDirectory("Choose directory") ?: return@action
task.exportToJson(
"${dir.absolutePath}/${task.name}.json",
onSuccessAction = ::showExtractionSuccessfulMessage,
onErrorAction = ::showFailedToExportToJsonError
)
}
}

Expand Down Expand Up @@ -321,8 +366,8 @@ class CompetitionsView: BaseView<CompetitionsViewModel>(CompetitionsViewModel(),
val file = chooseFile(
"Choose file",
filters = arrayOf(FileChooser.ExtensionFilter("*", "*.*"))
).firstOrNull()
attachmentContent.text = file?.absolutePath ?: ""
).firstOrNull() ?: return@action
attachmentContent.text = file.absolutePath.replace(File("").absolutePath, ".")
}
}
add(attachmentContent)
Expand Down Expand Up @@ -413,11 +458,29 @@ class CompetitionsView: BaseView<CompetitionsViewModel>(CompetitionsViewModel(),
}
}

private fun showFailedToParseJson() {
private fun showFailedToParseJsonError() {
alert(
Alert.AlertType.ERROR,
header = "JSON parsing failed",
"Failed to import tasks from JSON, check your JSON file",
"Failed to import competitions or tasks from JSON, check your JSON file",
ButtonType.OK
)
}

private fun showFailedToExportToJsonError() {
alert(
Alert.AlertType.ERROR,
header = "Exporting failed",
"Failed to export competition or task to JSON, check your JSON file",
ButtonType.OK
)
}

private fun showExtractionSuccessfulMessage() {
alert(
Alert.AlertType.INFORMATION,
header = "Success",
"Entity successfully exported",
ButtonType.OK
)
}
Expand Down
74 changes: 68 additions & 6 deletions src/main/kotlin/ui/competitions/CompetitionsViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package ui.competitions

import database.*
import javafx.beans.property.ReadOnlyStringProperty
import javafx.beans.property.ReadOnlyStringWrapper
import javafx.beans.property.SimpleStringProperty
import javafx.collections.ObservableList
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.javafx.JavaFx
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import tornadofx.toObservable
import ui.BaseViewModel
Expand Down Expand Up @@ -55,12 +56,43 @@ class CompetitionsViewModel: BaseViewModel() {
try {
val text = file.readText()
val parse = Json.decodeFromString<Array<TaskModel>>(text)
for (task in parse) {
DbHelper.add(dto, task)
for (task in parse) DbHelper.add(dto, task)
} catch (ex: Exception) {
withContext(Dispatchers.JavaFx) { onErrorAction() }
Logger.error(
tag,
"Failed to parse tasks from JSON. ${ex.message}\n${ex.stackTraceToString()}"
)
}
}
}

fun exportToJson(file: String, onSuccessAction: () -> Unit, onErrorAction: () -> Unit) {
viewModelScope.launch {
try {
val tasks = dto.getTasks().map {
TaskModel(
it.category,
it.name,
it.description,
it.flag,
it.attachment
)
}
val text = Json.encodeToString(arrayOf(
CompetitionModel(
dto.name,
tasks
)
))
File(file).writeText(text)
withContext(Dispatchers.JavaFx) { onSuccessAction() }
} catch (ex: Exception) {
onErrorAction()
Logger.error(tag, "Failed to decode JSON. ${ex.message}\n${ex.stackTraceToString()}")
withContext(Dispatchers.JavaFx) { onErrorAction() }
Logger.error(
tag,
"Failed to extract competition to JSON. ${ex.message}\n${ex.stackTraceToString()}"
)
}
}
}
Expand All @@ -80,6 +112,20 @@ class CompetitionsViewModel: BaseViewModel() {

fun delete() { viewModelScope.launch { DbHelper.delete(dto) } }

fun exportToJson(file: String, onSuccessAction: () -> Unit, onErrorAction: () -> Unit) {
viewModelScope.launch {
try {
val text = Json.encodeToString(arrayOf(
TaskModel(category, name, description, flag, attachment)
))
File(file).writeText(text)
withContext(Dispatchers.JavaFx) { onSuccessAction() }
} catch (ex: Exception) {
withContext(Dispatchers.JavaFx) { onErrorAction() }
Logger.error(tag, "Failed to export task to JSON: ${ex.message}\n${ex.stackTraceToString()}")
}
}
}
fun pushChanges() { viewModelScope.launch { dto.updateEntity() } }
}

Expand All @@ -106,7 +152,7 @@ class CompetitionsViewModel: BaseViewModel() {
}

private val mCompetitionName = ReadOnlyStringWrapper("")
val competitionName = mCompetitionName.readOnlyProperty
val competitionName: ReadOnlyStringProperty = mCompetitionName.readOnlyProperty

val competitions: ObservableList<CompetitionItem> = emptyList<CompetitionItem>().toObservable()
val tasks: ObservableList<TaskItem> = emptyList<TaskItem>().toObservable()
Expand Down Expand Up @@ -170,4 +216,20 @@ class CompetitionsViewModel: BaseViewModel() {
}
}
}

fun addCompetitionsFromJson(file: File, onErrorAction: () -> Unit) {
viewModelScope.launch {
try {
val text = file.readText()
val parse = Json.decodeFromString<Array<CompetitionModel>>(text)
for (competition in parse) DbHelper.add(competition)
} catch (ex: Exception) {
withContext(Dispatchers.JavaFx) { onErrorAction() }
Logger.error(
tag,
"Failed to parse competitions from JSON. ${ex.message}\n${ex.stackTraceToString()}"
)
}
}
}
}
3 changes: 2 additions & 1 deletion src/main/kotlin/ui/main/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ui.main
import bot.BotManager
import database.CompetitionDTO
import database.DbHelper
import javafx.beans.property.ReadOnlyBooleanProperty
import javafx.beans.property.ReadOnlyBooleanWrapper
import javafx.collections.ObservableList
import kotlinx.coroutines.*
Expand All @@ -22,7 +23,7 @@ class MainViewModel: BaseViewModel() {
)

private val mIsRunning = ReadOnlyBooleanWrapper(false)
val isRunning = mIsRunning.readOnlyProperty
val isRunning: ReadOnlyBooleanProperty = mIsRunning.readOnlyProperty

val competitions: ObservableList<CompetitionItem> = emptyList<CompetitionItem>().toObservable()
private val dbEvents = DbHelper.eventsPipe
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/ui/players/PlayersViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ui.players

import bot.BotManager
import database.*
import javafx.beans.property.ReadOnlyStringProperty
import javafx.beans.property.ReadOnlyStringWrapper
import javafx.collections.transformation.SortedList
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -88,10 +89,10 @@ class PlayersViewModel: BaseViewModel() {
}

private val mPlayerName = ReadOnlyStringWrapper("")
val playerName = mPlayerName.readOnlyProperty
val playerName: ReadOnlyStringProperty = mPlayerName.readOnlyProperty

private val mPlayerScore = ReadOnlyStringWrapper("")
val playerScore = mPlayerScore.readOnlyProperty
val playerScore: ReadOnlyStringProperty = mPlayerScore.readOnlyProperty

private val players = emptyList<PlayerItem>().toObservable()
val scoreBoard = SortedList(players) { o1, o2 -> o2.totalScore - o1.totalScore }
Expand Down

0 comments on commit dbf2db6

Please sign in to comment.