SaveSlotManager class
Manages multiple independent save slots (separate characters/profiles) on the same device — the classic "3 save files, pick a character on the home screen" casual/mid-core game pattern.
Deliberately a THIN coordinator, same posture as
OnboardingCoordinatorService (IDEA-54) for a completely different
domain: this only tracks slot metadata (id/display name/timestamps) and
which slot is active, and hands out a namespaced keyFor a caller uses
with their OWN VersionedJsonStore for the actual player-profile JSON.
It never defines that schema itself — every game's profile shape is
different, and this doesn't replace VersionedJsonStore (FEAT-05), it
composes with it.
- Inheritance
-
- Object
- GetLifeCycle
- DisposableInterface
- GetxService
- SaveSlotManager
Constructors
- SaveSlotManager({int? maxSlots})
Properties
- activeSlotId → String?
-
The currently active slot id, or
nullif none has been set yet. Persists across restart. Reads straight through to StorageService rather than caching a copy here — it's a single plain key, not the burst-write-prone slot LIST, so there's no race to guard against and no reason to duplicate stateStorageServicealready holds.no setter - canCreateSlot → bool
-
trueif createSlot can be called right now without throwing — alwaystruewhen maxSlots isnull(unlimited). A UI checks this to decide whether to disable a "Create slot" button, rather than re-deriving the samemaxSlots == null || ...null-check itself.no setter -
debugPendingSaves
→ Future<
void> -
Awaits every save queued so far — lets a test deterministically wait
for a burst of rapid calls to fully settle instead of guessing a delay.
no setter
- hashCode → int
-
The hash code for this object.
no setterinherited
- initialized → bool
-
Checks whether the controller has already been initialized.
no setterinherited
- isClosed → bool
-
Checks whether the controller has already been closed.
no setterinherited
- maxSlots → int?
-
ENH-68: caps how many slots createSlot will allow —
null(default) means unlimited, unchanged from before this existed. Deliberately not defaulted to a specific number (3? 5?): how many save slots a game offers is a product decision for the consumer app, not this package.final -
onDelete
→ InternalFinalCallback<
void> -
Internal callback that starts the cycle of this controller.
finalinherited
-
onStart
→ InternalFinalCallback<
void> -
Called at the exact moment the widget is allocated in memory.
It uses an internal "callable" type, to avoid any @overrides in subclases.
This method should be internal and is required to define the
lifetime cycle of the subclass.
finalinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
$configureLifeCycle(
) → void -
inherited
-
createSlot(
String displayName) → SaveSlotMeta -
Creates a new slot with a freshly-generated, guaranteed-unique id
(even across a burst of rapid calls in the same millisecond).
createdAtMs/lastPlayedAtMsboth start atnowMsClamped()— the same anti-clock-rewind clock every time-gated system in this package uses, never rawDateTime.now(). -
deleteSlot(
String id) → Future< void> -
Deletes slot
id: removes its metadata AND every key namespaced to it via keyFor (throughStorageService.removeAllWithPrefix) — no leftover keys from a deleted slot. Ifidwas the activeSlotId, that becomesnullafterward (never left pointing at a slot that no longer exists). ThrowsArgumentErrorifiddoesn't exist. -
keyFor(
String slotId, String suffix) → String -
A key namespaced to
slotIdforsuffix— hand this to aVersionedJsonStore's ownkey:for that slot's player-profile data. Stable/deterministic (same inputs always produce the same key). EveryslotIdis always one this class generated itself via_generateUniqueId(slot_<digits>, never containing an underscore-delimited component that could extend another id's own prefix — see that method's own doc for why that property matters for deleteSlot'sremoveAllWithPrefixcall), so 2 differentslotId/suffixpairs can never collide. -
listSlots(
) → List< SaveSlotMeta> - Every slot, most-recently-played first — the classic "Continue" UX.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
onClose(
) → void -
Called before
onDeletemethod.onClosemight be used to dispose resources used by the controller. Like closing events, or streams before the controller is destroyed. Or dispose objects that can potentially create some memory leaks, like TextEditingControllers, AnimationControllers. Might be useful as well to persist some data on disk.inherited -
onInit(
) → void -
Called immediately after the widget is allocated in memory.
You might use this to initialize something for the controller.
inherited
-
onReady(
) → void -
Called 1 frame after onInit(). It is the perfect place to enter
navigation events, like snackbar, dialogs, or a new route, or
async request.
inherited
-
renameSlot(
String id, String newDisplayName) → void -
Renames slot
id. ThrowsArgumentErrorifiddoesn't exist. -
restoreSlotMeta(
SaveSlotMeta meta) → void -
Registers/updates
metadirectly in the slot list — BUG-41: used by disaster-recovery restore (DisasterRecoverySaveExport.applyRestore) right after it restores a slot's actual data viaStorageService.importWithPrefix, which only writes the slot's namespaced keys and never touches this manager's own separate_metaStorageKeylist — without this, the restored data exists on disk but listSlots never surfaces it (an orphaned slot). -
setActiveSlot(
String id) → Future< void> -
Marks
idas the active slot. ThrowsArgumentError(without changing activeSlotId) ifiddoesn't exist — never actives into a slot that was never created (or was already deleted). -
toString(
) → String -
A string representation of this object.
inherited
-
touchSlot(
String id) → void -
Bumps slot
id'slastPlayedAtMsto now — call when a play session in that slot starts, so listSlots surfaces it first next time. ThrowsArgumentErrorifiddoesn't exist.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
- maybe → SaveSlotManager?
-
Gets the instance if already registered (safe to call from
game/widget tests).
no setter