refactor(privacy): drop I2pType.INTERNAL — EXTERNAL is the permanent answer

Earlier commits kept I2pType.INTERNAL as a placeholder for a follow-up
embedded daemon. We're not shipping that: I2P bootstrap on Android is
structurally minutes-long (no equivalent of Tor's hardcoded directory
authorities — NetDB peer discovery is protocol-inherent), so an embedded
router would mean a permanently-warming UX. Users who want I2P run i2pd /
Java I2P independently and point Amethyst at its SOCKS port.

Changes:
- commons I2pType drops the INTERNAL variant; parseI2pType collapses unknown
  codes to OFF
- I2pManager loses its INTERNAL switch arm
- I2pSettingsDialog drops the "treat INTERNAL as OFF" mapping it used to
  carry — the enum no longer has the case
- Android UI I2pSettings.resourceId drops the i2p_internal branch
- strings.xml drops the now-unused i2p_internal string
- I2pSharedPreferences hardens load: a stored "INTERNAL" from an earlier
  branch is no longer a valid I2pType, so runCatching swallows the
  IllegalArgumentException and the user lands on OFF
- PrivacyRouterTest fixtures use I2pType.EXTERNAL throughout
This commit is contained in:
Claude
2026-05-19 20:37:53 +00:00
parent 4e796c8e8b
commit 40995b9670
7 changed files with 29 additions and 29 deletions
@@ -41,17 +41,20 @@ data class I2pSettings(
val mediaUploadsViaI2p: Boolean = false,
)
// EXTERNAL-only: this app does not embed an I2P router. Bootstrap on Android is
// minutes-long for a fresh netDb and the protocol provides no shortcut analogous
// to Tor's hardcoded directory authorities; we'd ship a "permanently warming up"
// experience. Users who want I2P run i2pd or Java I2P independently and point
// Amethyst at its SOCKS port (default 4447). See I2pManager.
enum class I2pType(
val screenCode: Int,
) {
OFF(0),
INTERNAL(1),
EXTERNAL(2),
}
fun parseI2pType(code: Int?): I2pType =
when (code) {
I2pType.INTERNAL.screenCode -> I2pType.INTERNAL
I2pType.EXTERNAL.screenCode -> I2pType.EXTERNAL
else -> I2pType.OFF
}
@@ -38,7 +38,7 @@ class PrivacyRouterTest {
i2pOn: Boolean = false,
preferred: PrivacyTransport = PrivacyTransport.DIRECT,
tor: TorSettings = TorSettings(torType = if (torOn) TorType.INTERNAL else TorType.OFF),
i2p: I2pSettings = I2pSettings(i2pType = if (i2pOn) I2pType.INTERNAL else I2pType.OFF),
i2p: I2pSettings = I2pSettings(i2pType = if (i2pOn) I2pType.EXTERNAL else I2pType.OFF),
) = PrivacySettings(
tor = tor,
i2p = i2p,
@@ -125,7 +125,7 @@ class PrivacyRouterTest {
settings(
i2pOn = true,
preferred = PrivacyTransport.I2P,
i2p = I2pSettings(i2pType = I2pType.INTERNAL, videosViaI2p = true),
i2p = I2pSettings(i2pType = I2pType.EXTERNAL, videosViaI2p = true),
)
assertEquals(PrivacyRoute.I2p, PrivacyRouter.route(clearnet, FeatureRole.VIDEO, s))
}
@@ -136,7 +136,7 @@ class PrivacyRouterTest {
settings(
i2pOn = true,
preferred = PrivacyTransport.I2P,
i2p = I2pSettings(i2pType = I2pType.INTERNAL, videosViaI2p = false),
i2p = I2pSettings(i2pType = I2pType.EXTERNAL, videosViaI2p = false),
)
assertEquals(PrivacyRoute.Direct, PrivacyRouter.route(clearnet, FeatureRole.VIDEO, s))
}
@@ -162,7 +162,7 @@ class PrivacyRouterTest {
torOn = false,
i2pOn = true,
preferred = PrivacyTransport.TOR,
i2p = I2pSettings(i2pType = I2pType.INTERNAL, imagesViaI2p = true),
i2p = I2pSettings(i2pType = I2pType.EXTERNAL, imagesViaI2p = true),
)
assertEquals(PrivacyRoute.Direct, PrivacyRouter.route(clearnet, FeatureRole.IMAGE, s))
}
@@ -176,7 +176,7 @@ class PrivacyRouterTest {
i2pOn = true,
preferred = PrivacyTransport.I2P,
tor = TorSettings(torType = TorType.INTERNAL, imagesViaTor = true),
i2p = I2pSettings(i2pType = I2pType.INTERNAL, imagesViaI2p = true),
i2p = I2pSettings(i2pType = I2pType.EXTERNAL, imagesViaI2p = true),
)
assertEquals(PrivacyRoute.I2p, PrivacyRouter.route(clearnet, FeatureRole.IMAGE, s))
}