Add delete option for save state slots
Add deleteState method to EmulatorCore interface and implement in Ps1Core and NesCore. Delete button (trash icon) in the in-game Save/Load menu removes the state file and its screenshot, then refreshes the slot list.
This commit is contained in:
@@ -42,6 +42,8 @@ interface EmulatorCore {
|
|||||||
|
|
||||||
fun loadState(slot: Int): Boolean
|
fun loadState(slot: Int): Boolean
|
||||||
|
|
||||||
|
fun deleteState(slot: Int): Boolean = false
|
||||||
|
|
||||||
fun getSaveSlotInfo(slot: Int): SaveSlotInfo
|
fun getSaveSlotInfo(slot: Int): SaveSlotInfo
|
||||||
|
|
||||||
fun getScreenshotPath(slot: Int): String? = null
|
fun getScreenshotPath(slot: Int): String? = null
|
||||||
|
|||||||
@@ -120,6 +120,14 @@ class NesCore(
|
|||||||
return NativeLibretro.nativeLoadState(path)
|
return NativeLibretro.nativeLoadState(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deleteState(slot: Int): Boolean {
|
||||||
|
val state = File(savesDir, "state_$slot.sav")
|
||||||
|
val screenshot = File(savesDir, "state_$slot.jpg")
|
||||||
|
val deleted = state.exists() && state.delete()
|
||||||
|
if (screenshot.exists()) screenshot.delete()
|
||||||
|
return deleted
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSaveSlotInfo(slot: Int): SaveSlotInfo {
|
override fun getSaveSlotInfo(slot: Int): SaveSlotInfo {
|
||||||
val file = File(savesDir, "state_$slot.sav")
|
val file = File(savesDir, "state_$slot.sav")
|
||||||
val screenshot = File(savesDir, "state_$slot.jpg")
|
val screenshot = File(savesDir, "state_$slot.jpg")
|
||||||
|
|||||||
@@ -140,6 +140,14 @@ class Ps1Core(
|
|||||||
return NativeLibretro.nativeLoadState(path)
|
return NativeLibretro.nativeLoadState(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deleteState(slot: Int): Boolean {
|
||||||
|
val state = File(savesDir, "state_$slot.sav")
|
||||||
|
val screenshot = File(savesDir, "state_$slot.jpg")
|
||||||
|
val deleted = state.exists() && state.delete()
|
||||||
|
if (screenshot.exists()) screenshot.delete()
|
||||||
|
return deleted
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSaveSlotInfo(slot: Int): SaveSlotInfo {
|
override fun getSaveSlotInfo(slot: Int): SaveSlotInfo {
|
||||||
val file = File(savesDir, "state_$slot.sav")
|
val file = File(savesDir, "state_$slot.sav")
|
||||||
val screenshot = File(savesDir, "state_$slot.jpg")
|
val screenshot = File(savesDir, "state_$slot.jpg")
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.AspectRatio
|
import androidx.compose.material.icons.filled.AspectRatio
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
import androidx.compose.material.icons.filled.Pause
|
import androidx.compose.material.icons.filled.Pause
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
@@ -309,6 +310,11 @@ fun GameScreen(
|
|||||||
if (!isPaused) c.resume()
|
if (!isPaused) c.resume()
|
||||||
showGameMenu = false
|
showGameMenu = false
|
||||||
},
|
},
|
||||||
|
onDelete = { slot ->
|
||||||
|
val c = core ?: return@GameMenu
|
||||||
|
c.deleteState(slot)
|
||||||
|
saveSlots = c.getAllSaveSlots()
|
||||||
|
},
|
||||||
onResume = {
|
onResume = {
|
||||||
if (!isPaused) core?.resume()
|
if (!isPaused) core?.resume()
|
||||||
showGameMenu = false
|
showGameMenu = false
|
||||||
@@ -436,6 +442,7 @@ private fun GameMenu(
|
|||||||
slots: List<SaveSlotInfo>,
|
slots: List<SaveSlotInfo>,
|
||||||
onSave: (slot: Int) -> Unit,
|
onSave: (slot: Int) -> Unit,
|
||||||
onLoad: (slot: Int) -> Unit,
|
onLoad: (slot: Int) -> Unit,
|
||||||
|
onDelete: (slot: Int) -> Unit,
|
||||||
onResume: () -> Unit
|
onResume: () -> Unit
|
||||||
) {
|
) {
|
||||||
val dateFormat = remember { SimpleDateFormat("MMM d, yyyy h:mm a", Locale.getDefault()) }
|
val dateFormat = remember { SimpleDateFormat("MMM d, yyyy h:mm a", Locale.getDefault()) }
|
||||||
@@ -534,6 +541,19 @@ private fun GameMenu(
|
|||||||
) {
|
) {
|
||||||
Text("Load", style = MaterialTheme.typography.labelMedium)
|
Text("Load", style = MaterialTheme.typography.labelMedium)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
IconButton(
|
||||||
|
onClick = { onDelete(slot.slot) },
|
||||||
|
enabled = slot.exists,
|
||||||
|
modifier = Modifier.size(36.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Delete,
|
||||||
|
contentDescription = "Delete save",
|
||||||
|
tint = if (slot.exists) Color.White.copy(alpha = 0.7f) else Color.White.copy(alpha = 0.2f)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user