Rename save/load completion callbacks for custom locations and implement error handling
This commit is contained in:
parent
f9b43c9b61
commit
a4d3e80f57
6 changed files with 102 additions and 54 deletions
|
@ -28,7 +28,7 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
|
|||
@GuardedBy("this")
|
||||
private val callbacks = ArrayList<IndexedCallback>()
|
||||
|
||||
override fun saveGame(gameInfo: GameInfo, gameName: String, forcePrompt: Boolean, block: (() -> Unit)?) {
|
||||
override fun saveGame(gameInfo: GameInfo, gameName: String, forcePrompt: Boolean, saveCompleteCallback: ((Exception?) -> Unit)?) {
|
||||
val callbackIndex = synchronized(this) {
|
||||
val index = callbackIndex++
|
||||
callbacks.add(IndexedCallback(
|
||||
|
@ -36,8 +36,10 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
|
|||
{ uri ->
|
||||
if (uri != null) {
|
||||
saveGame(gameInfo, uri)
|
||||
saveCompleteCallback?.invoke(null)
|
||||
} else {
|
||||
saveCompleteCallback?.invoke(RuntimeException("Uri was null"))
|
||||
}
|
||||
block?.invoke()
|
||||
}
|
||||
))
|
||||
index
|
||||
|
@ -76,25 +78,33 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
|
|||
}
|
||||
}
|
||||
|
||||
override fun loadGame(block: (GameInfo) -> Unit) {
|
||||
override fun loadGame(loadCompleteCallback: (GameInfo?, Exception?) -> Unit) {
|
||||
val callbackIndex = synchronized(this) {
|
||||
val index = callbackIndex++
|
||||
callbacks.add(IndexedCallback(
|
||||
index,
|
||||
callback@{ uri ->
|
||||
if (uri == null) return@callback
|
||||
val game = activity.contentResolver.openInputStream(uri)
|
||||
?.reader()
|
||||
?.readText()
|
||||
?.run {
|
||||
GameSaver.gameInfoFromString(this)
|
||||
}
|
||||
var exception: Exception? = null
|
||||
val game = try {
|
||||
activity.contentResolver.openInputStream(uri)
|
||||
?.reader()
|
||||
?.readText()
|
||||
?.run {
|
||||
GameSaver.gameInfoFromString(this)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
exception = e
|
||||
null
|
||||
}
|
||||
if (game != null) {
|
||||
// If the user has saved the game from another platform (like Android),
|
||||
// then the save location might not be right so we have to correct for that
|
||||
// here
|
||||
game.customSaveLocation = uri.toString()
|
||||
block(game)
|
||||
loadCompleteCallback(game, null)
|
||||
} else {
|
||||
loadCompleteCallback(null, RuntimeException("Failed to load save game", exception))
|
||||
}
|
||||
}
|
||||
))
|
||||
|
|
|
@ -6,8 +6,8 @@ package com.unciv.logic
|
|||
*/
|
||||
interface CustomSaveLocationHelper {
|
||||
/**
|
||||
* Saves a game asynchronously with a given default name and then calls the [block] callback
|
||||
* upon completion. The [block] callback will be called from the same thread that this method
|
||||
* Saves a game asynchronously with a given default name and then calls the [saveCompleteCallback] callback
|
||||
* upon completion. The [saveCompleteCallback] callback will be called from the same thread that this method
|
||||
* is called from. If the [GameInfo] object already has the
|
||||
* [customSaveLocation][GameInfo.customSaveLocation] property defined (not null), then the user
|
||||
* will not be prompted to select a location for the save unless [forcePrompt] is set to true
|
||||
|
@ -17,12 +17,12 @@ interface CustomSaveLocationHelper {
|
|||
gameInfo: GameInfo,
|
||||
gameName: String,
|
||||
forcePrompt: Boolean = false,
|
||||
block: (() -> Unit)? = null
|
||||
saveCompleteCallback: ((Exception?) -> Unit)? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* Loads a game from an external source asynchronously, then calls [block] with the loaded
|
||||
* Loads a game from an external source asynchronously, then calls [loadCompleteCallback] with the loaded
|
||||
* [GameInfo]
|
||||
*/
|
||||
fun loadGame(block: (GameInfo) -> Unit)
|
||||
fun loadGame(loadCompleteCallback: (GameInfo?, Exception?) -> Unit)
|
||||
}
|
||||
|
|
|
@ -39,19 +39,19 @@ object GameSaver {
|
|||
return localSaves + Gdx.files.absolute(externalFilesDirForAndroid + "/${getSubfolder(multiplayer)}").list().asSequence()
|
||||
}
|
||||
|
||||
fun saveGame(game: GameInfo, GameName: String, multiplayer: Boolean = false, forcePrompt: Boolean = false, block: (() -> Unit)? = null) {
|
||||
fun saveGame(game: GameInfo, GameName: String, multiplayer: Boolean = false, forcePrompt: Boolean = false, saveCompletionCallback: ((Exception?) -> Unit)? = null) {
|
||||
val customSaveLocation = game.customSaveLocation
|
||||
val customSaveLocationHelper = this.customSaveLocationHelper
|
||||
if (customSaveLocation != null && customSaveLocationHelper != null) {
|
||||
customSaveLocationHelper.saveGame(game, GameName, forcePrompt, block)
|
||||
customSaveLocationHelper.saveGame(game, GameName, forcePrompt, saveCompletionCallback)
|
||||
} else {
|
||||
json().toJson(game,getSave(GameName, multiplayer))
|
||||
block?.invoke()
|
||||
json().toJson(game, getSave(GameName, multiplayer))
|
||||
saveCompletionCallback?.invoke(null)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveGameToCustomLocation(game: GameInfo, GameName: String, block: () -> Unit) {
|
||||
customSaveLocationHelper!!.saveGame(game, GameName, forcePrompt = true, block =block)
|
||||
fun saveGameToCustomLocation(game: GameInfo, GameName: String, saveCompletionCallback: (Exception?) -> Unit) {
|
||||
customSaveLocationHelper!!.saveGame(game, GameName, forcePrompt = true, saveCompleteCallback = saveCompletionCallback)
|
||||
}
|
||||
|
||||
fun loadGameByName(GameName: String, multiplayer: Boolean = false) =
|
||||
|
@ -63,15 +63,15 @@ object GameSaver {
|
|||
return game
|
||||
}
|
||||
|
||||
fun loadGameFromCustomLocation(block: (GameInfo) -> Unit) {
|
||||
customSaveLocationHelper!!.loadGame { game ->
|
||||
block(game.apply { setTransients() })
|
||||
fun loadGameFromCustomLocation(loadCompletionCallback: (GameInfo?, Exception?) -> Unit) {
|
||||
customSaveLocationHelper!!.loadGame { game, e ->
|
||||
loadCompletionCallback(game?.apply { setTransients() }, e)
|
||||
}
|
||||
}
|
||||
|
||||
fun canLoadFromCustomSaveLocation() = customSaveLocationHelper != null
|
||||
|
||||
fun gameInfoFromString(gameData:String): GameInfo {
|
||||
fun gameInfoFromString(gameData: String): GameInfo {
|
||||
val game = json().fromJson(GameInfo::class.java, gameData)
|
||||
game.setTransients()
|
||||
return game
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.unciv.ui.pickerscreens.PickerScreen
|
|||
import com.unciv.ui.utils.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.CancellationException
|
||||
import kotlin.concurrent.thread
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
|
||||
|
@ -81,8 +82,13 @@ class LoadGameScreen(previousScreen:CameraStageBaseScreen) : PickerScreen() {
|
|||
if (GameSaver.canLoadFromCustomSaveLocation()) {
|
||||
val loadFromCustomLocation = "Load from custom location".toTextButton()
|
||||
loadFromCustomLocation.onClick {
|
||||
GameSaver.loadGameFromCustomLocation {
|
||||
game.loadGame(it)
|
||||
GameSaver.loadGameFromCustomLocation { gameInfo, exception ->
|
||||
if (gameInfo != null) {
|
||||
game.loadGame(gameInfo)
|
||||
} else if (exception !is CancellationException) {
|
||||
errorLabel.setText("Could not load game from custom location!".tr())
|
||||
exception?.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
rightSideTable.add(loadFromCustomLocation).pad(10f).row()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.unciv.ui.saves
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextField
|
||||
|
@ -10,6 +11,7 @@ import com.unciv.logic.GameSaver
|
|||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.pickerscreens.PickerScreen
|
||||
import com.unciv.ui.utils.*
|
||||
import java.util.concurrent.CancellationException
|
||||
import kotlin.concurrent.thread
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
|
||||
|
@ -42,17 +44,26 @@ class SaveGameScreen : PickerScreen() {
|
|||
newSave.add(copyJsonButton).row()
|
||||
if (GameSaver.canLoadFromCustomSaveLocation()) {
|
||||
val saveToCustomLocation = "Save to custom location".toTextButton()
|
||||
val errorLabel = "".toLabel(Color.RED)
|
||||
saveToCustomLocation.enable()
|
||||
saveToCustomLocation.onClick {
|
||||
errorLabel.setText("")
|
||||
saveToCustomLocation.setText("Saving...".tr())
|
||||
saveToCustomLocation.disable()
|
||||
thread(name = "SaveGame") {
|
||||
GameSaver.saveGameToCustomLocation(UncivGame.Current.gameInfo, textField.text) {
|
||||
Gdx.app.postRunnable { UncivGame.Current.setWorldScreen() }
|
||||
GameSaver.saveGameToCustomLocation(UncivGame.Current.gameInfo, textField.text) { e ->
|
||||
if (e == null) {
|
||||
Gdx.app.postRunnable { UncivGame.Current.setWorldScreen() }
|
||||
} else if (e !is CancellationException) {
|
||||
errorLabel.setText("Could not save game to custom location".tr())
|
||||
e.printStackTrace()
|
||||
}
|
||||
saveToCustomLocation.enable()
|
||||
}
|
||||
}
|
||||
}
|
||||
newSave.add(saveToCustomLocation).pad(10f).row()
|
||||
newSave.add(errorLabel).pad(0f, 10f, 10f, 10f).row()
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,19 +7,24 @@ import com.unciv.logic.GameSaver
|
|||
import com.unciv.logic.GameSaver.json
|
||||
import java.awt.event.WindowEvent
|
||||
import java.io.File
|
||||
import java.util.concurrent.CancellationException
|
||||
import javax.swing.JFileChooser
|
||||
import javax.swing.JFrame
|
||||
|
||||
class CustomSaveLocationHelperDesktop : CustomSaveLocationHelper {
|
||||
override fun saveGame(gameInfo: GameInfo, gameName: String, forcePrompt: Boolean, block: (() -> Unit)?) {
|
||||
override fun saveGame(gameInfo: GameInfo, gameName: String, forcePrompt: Boolean, saveCompleteCallback: ((Exception?) -> Unit)?) {
|
||||
val customSaveLocation = gameInfo.customSaveLocation
|
||||
if (customSaveLocation != null && !forcePrompt) {
|
||||
File(customSaveLocation).outputStream()
|
||||
.writer()
|
||||
.use { writer ->
|
||||
writer.write(json().toJson(gameInfo))
|
||||
}
|
||||
block?.invoke()
|
||||
try {
|
||||
File(customSaveLocation).outputStream()
|
||||
.writer()
|
||||
.use { writer ->
|
||||
writer.write(json().toJson(gameInfo))
|
||||
}
|
||||
saveCompleteCallback?.invoke(null)
|
||||
} catch (e: Exception) {
|
||||
saveCompleteCallback?.invoke(e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -36,18 +41,25 @@ class CustomSaveLocationHelperDesktop : CustomSaveLocationHelper {
|
|||
dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING))
|
||||
}
|
||||
val file = fileChooser.selectedFile
|
||||
var exception: Exception? = null
|
||||
if (file != null) {
|
||||
gameInfo.customSaveLocation = file.absolutePath
|
||||
file.outputStream()
|
||||
.writer()
|
||||
.use {
|
||||
it.write(json().toJson(gameInfo))
|
||||
}
|
||||
try {
|
||||
file.outputStream()
|
||||
.writer()
|
||||
.use {
|
||||
it.write(json().toJson(gameInfo))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
exception = e
|
||||
}
|
||||
} else {
|
||||
exception = CancellationException()
|
||||
}
|
||||
block?.invoke()
|
||||
saveCompleteCallback?.invoke(exception)
|
||||
}
|
||||
|
||||
override fun loadGame(block: (GameInfo) -> Unit) {
|
||||
override fun loadGame(loadCompleteCallback: (GameInfo?, Exception?) -> Unit) {
|
||||
val fileChooser = JFileChooser().apply fileChooser@{
|
||||
currentDirectory = Gdx.files.local("").file()
|
||||
}
|
||||
|
@ -60,18 +72,27 @@ class CustomSaveLocationHelperDesktop : CustomSaveLocationHelper {
|
|||
dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING))
|
||||
}
|
||||
val file = fileChooser.selectedFile
|
||||
var exception: Exception? = null
|
||||
var gameInfo: GameInfo? = null
|
||||
if (file != null) {
|
||||
file.inputStream()
|
||||
.reader()
|
||||
.readText()
|
||||
.run { GameSaver.gameInfoFromString(this) }
|
||||
.apply {
|
||||
// If the user has saved the game from another platform (like Android),
|
||||
// then the save location might not be right so we have to correct for that
|
||||
// here
|
||||
customSaveLocation = file.absolutePath
|
||||
block(this)
|
||||
}
|
||||
try {
|
||||
file.inputStream()
|
||||
.reader()
|
||||
.readText()
|
||||
.run { GameSaver.gameInfoFromString(this) }
|
||||
.apply {
|
||||
// If the user has saved the game from another platform (like Android),
|
||||
// then the save location might not be right so we have to correct for that
|
||||
// here
|
||||
customSaveLocation = file.absolutePath
|
||||
gameInfo = this
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
exception = e
|
||||
}
|
||||
} else {
|
||||
exception = CancellationException()
|
||||
}
|
||||
loadCompleteCallback(gameInfo, exception)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue