mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 11:01:07 +00:00
Game storage is automatic: a card in the phone is a Steam library by itself
The choice belongs inside the client - the drive drop-down on Install, Settings > Storage - so the app no longer needs a setting for the common case. Default = automatic (the first SD card present); the cog keeps Internal only and a chosen folder.
This commit is contained in:
1 parent
fa25451766
commit
1374091d1b
7 files changed
+43
-16
No files matched your search
@@ -174,9 +174,11 @@ under proot; Firefox's are turned off in the session's environment, without whic
|
||||
|
||||
### Game storage: internal, an SD card, or a folder
|
||||
|
||||
The client's own library is internal storage and always there. **Game storage** in the Steam cog
|
||||
registers one more: an SD card (through the app's own folder on it, the one place a card lets
|
||||
this app write) or any folder chosen in the File Manager. The session binds it at
|
||||
The client's own library is internal storage and always there. An **SD card in the phone is
|
||||
registered as a second library by itself** (through the app's own folder on it, the one place a
|
||||
card lets this app write), so the choice is made where it is anywhere else - inside Steam, on
|
||||
every Install. **Game storage** in the Steam cog is only for turning that off or pointing it at a
|
||||
folder chosen in the File Manager instead. The session binds it at
|
||||
`/mnt/bannerlator-sd` and `bannerlator-steam-library` registers it with the client under the name
|
||||
the app gives it; the client then asks where to install every game, lists both on its Storage
|
||||
page and moves games between them itself. Set to internal only, the entry is removed again. A
|
||||
|
||||
@@ -386,7 +386,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
/** A second Steam library, proven writable first; "" = internal only. */
|
||||
private fun setGameStorage(path: String, label: String) {
|
||||
if (path.isNotEmpty()) {
|
||||
if (path.isNotEmpty() && path != SessionPrefs.GAME_STORAGE_OFF) {
|
||||
val problem = GameStorage.prepare(path)
|
||||
if (problem != null) {
|
||||
android.widget.Toast.makeText(this, "Not usable: $problem", android.widget.Toast.LENGTH_LONG).show()
|
||||
|
||||
@@ -147,7 +147,11 @@ object DeviceReport {
|
||||
k("On-screen controls", SessionPrefs.oscMode(context))
|
||||
k("Touch mode", SessionPrefs.touchMode(context))
|
||||
k("Performance HUD", SessionPrefs.hudEnabled(context))
|
||||
k("Game storage", SessionPrefs.gameStorage(context).ifEmpty { "internal only" })
|
||||
k("Game storage", when (val g = SessionPrefs.gameStorage(context)) {
|
||||
"" -> "automatic (" + (com.steamdeck.launcher.session.GameStorage.effective(context)?.path ?: "no card present") + ")"
|
||||
SessionPrefs.GAME_STORAGE_OFF -> "internal only"
|
||||
else -> g
|
||||
})
|
||||
|
||||
h("Android process limits")
|
||||
// Android 12 kills "phantom" processes - the children an app forks itself rather than
|
||||
|
||||
@@ -53,6 +53,16 @@ object GameStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/** The root the session binds, from the setting: automatic = the first card in the phone. */
|
||||
fun effective(context: Context): Option? {
|
||||
val pref = SessionPrefs.gameStorage(context)
|
||||
return when {
|
||||
pref == SessionPrefs.GAME_STORAGE_OFF -> null
|
||||
pref.isEmpty() -> options(context).firstOrNull()?.let { Option(it.label.substringBefore(" ·"), it.path) }
|
||||
else -> Option(SessionPrefs.gameStorageLabel(context), pref)
|
||||
}
|
||||
}
|
||||
|
||||
/** The label the client shows for a chosen folder: its last name, or the volume's. */
|
||||
fun labelFor(context: Context, path: String): String =
|
||||
options(context).firstOrNull { it.path == path }?.label?.substringBefore(" ·")
|
||||
|
||||
@@ -229,10 +229,14 @@ object SessionPrefs {
|
||||
/**
|
||||
* A second Steam library on this device: the folder bound at /mnt/bannerlator-sd and
|
||||
* registered with the client, which then asks where to install every game and shows both
|
||||
* on its Storage page. "" = internal only (the client's own library, the default).
|
||||
* on its Storage page. "" = automatic: the SD card when one is in the phone (the default,
|
||||
* so the choice is made inside the client like anywhere else); GAME_STORAGE_OFF = internal
|
||||
* only; otherwise the folder chosen.
|
||||
*/
|
||||
fun gameStorage(context: Context): String = prefs(context).getString("gameStorage", "") ?: ""
|
||||
|
||||
const val GAME_STORAGE_OFF = "off"
|
||||
|
||||
fun gameStorageLabel(context: Context): String = prefs(context).getString("gameStorageLabel", "SD Card") ?: "SD Card"
|
||||
|
||||
fun setGameStorage(context: Context, path: String, label: String) {
|
||||
|
||||
@@ -324,17 +324,19 @@ class SessionService : Service() {
|
||||
// A second Steam library: the storage chosen in the Steam cog, at the path the runtime's
|
||||
// bannerlator-steam-library registers with the client. Nothing bound = the script removes
|
||||
// the entry, so the client never offers a place that is not there.
|
||||
val library = SessionPrefs.gameStorage(this).takeIf { it.isNotEmpty() }
|
||||
val library = GameStorage.effective(this)
|
||||
if (library != null) {
|
||||
val problem = GameStorage.prepare(library)
|
||||
val problem = GameStorage.prepare(library.path)
|
||||
if (problem == null) {
|
||||
File(LinuxRuntime.rootDir(this), "mnt/bannerlator-sd").mkdirs()
|
||||
binds.add("$library:/mnt/bannerlator-sd")
|
||||
guest.add("BL_LIBRARY_LABEL=" + SessionPrefs.gameStorageLabel(this).replace('"', ' '))
|
||||
Log.i(TAG, "game storage: $library -> /mnt/bannerlator-sd (\"${SessionPrefs.gameStorageLabel(this)}\")")
|
||||
binds.add("${library.path}:/mnt/bannerlator-sd")
|
||||
guest.add("BL_LIBRARY_LABEL=" + library.label.replace('"', ' '))
|
||||
Log.i(TAG, "game storage: ${library.path} -> /mnt/bannerlator-sd (\"${library.label}\")")
|
||||
} else {
|
||||
Log.w(TAG, "game storage: $problem; internal only this session")
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "game storage: internal only")
|
||||
}
|
||||
val roms = SessionPrefs.romsDir(this).takeIf { it.isNotEmpty() }?.let { File(it) }
|
||||
if (roms != null && roms.isDirectory && roms.canRead()) {
|
||||
|
||||
@@ -248,16 +248,21 @@ fun ModeSettingsDialog(s: ModeSettings, a: ModeSettingsActions) {
|
||||
"storage" -> if (s.gameStorage != null) {
|
||||
Section(
|
||||
"Game storage",
|
||||
"Where Steam may install games. Internal is the client's own library and always there. A second " +
|
||||
"place is registered with the client at the next session start: it then asks where to install " +
|
||||
"every game, lists both on its Storage page, and can move a game between them itself.",
|
||||
"The choice itself is made inside Steam: with a second place registered, every Install asks which " +
|
||||
"drive, Settings › Storage lists both, and Steam moves games between them. Internal is the " +
|
||||
"client's own library and always there. Applies at the next session start.",
|
||||
)
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Choice("Internal only — the default", s.gameStorage.isEmpty()) { a.onGameStorage("", "") }
|
||||
Choice(
|
||||
"Automatic — the SD card when one is in the phone" +
|
||||
(if (s.storageOptions.isEmpty()) " (none right now)" else ""),
|
||||
s.gameStorage.isEmpty(),
|
||||
) { a.onGameStorage("", "") }
|
||||
Choice("Internal only", s.gameStorage == "off") { a.onGameStorage("off", "") }
|
||||
for ((label, path) in s.storageOptions) {
|
||||
Choice(label, s.gameStorage == path) { a.onGameStorage(path, label.substringBefore(" ·")) }
|
||||
}
|
||||
val custom = s.gameStorage.isNotEmpty() && s.storageOptions.none { it.second == s.gameStorage }
|
||||
val custom = s.gameStorage.isNotEmpty() && s.gameStorage != "off" && s.storageOptions.none { it.second == s.gameStorage }
|
||||
if (custom) Choice("Folder: ${s.gameStorage}", true) {}
|
||||
OutlinedButton(onClick = a.onPickGameStorageFolder, modifier = Modifier.fillMaxWidth().padding(top = 8.dp)) {
|
||||
Text("Choose a folder…")
|
||||
|
||||
Reference in new issue
Block a user