From b355021b6f880fced3e9332355e8ba0bca74d216 Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sun, 8 Feb 2026 20:17:05 -0500 Subject: [PATCH] refactor: extract domain strings to AppConfig constants - Add LEGACY_TRMNL_DOMAIN and TRMNL_DOMAIN constants to AppConfig - Update TRMNL_API_SERVER_BASE_URL to use TRMNL_DOMAIN constant - Update TrmnlDeviceConfigDataStore to use domain constants - Update all test assertions to use AppConfig constants - Improves maintainability by centralizing domain configuration All 49 unit tests pass successfully. --- .../java/ink/trmnl/android/data/AppConfig.kt | 14 ++++- .../data/TrmnlDeviceConfigDataStore.kt | 4 +- .../data/TrmnlDeviceConfigDataStoreTest.kt | 60 +++++++++---------- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/ink/trmnl/android/data/AppConfig.kt b/app/src/main/java/ink/trmnl/android/data/AppConfig.kt index 9b5f753..26987cc 100644 --- a/app/src/main/java/ink/trmnl/android/data/AppConfig.kt +++ b/app/src/main/java/ink/trmnl/android/data/AppConfig.kt @@ -20,13 +20,25 @@ object AppConfig { */ const val DEFAULT_REFRESH_INTERVAL_SEC: Long = 7_200L // 2 hours + /** + * Legacy domain name for TRMNL API (deprecated, used for migration only). + * Ref: https://github.com/usetrmnl/trmnl-android/issues/240 + */ + const val LEGACY_TRMNL_DOMAIN = "usetrmnl.com" + + /** + * Current domain name for TRMNL API. + * Ref: https://github.com/usetrmnl/trmnl-android/issues/240 + */ + const val TRMNL_DOMAIN = "trmnl.com" + /** * Base URL for the TRMNL API server. * Ref: * - https://github.com/usetrmnl/trmnl-android/issues/171 * - https://github.com/usetrmnl/trmnl-android/issues/240 */ - const val TRMNL_API_SERVER_BASE_URL = "https://trmnl.com/" + const val TRMNL_API_SERVER_BASE_URL = "https://$TRMNL_DOMAIN/" /** * URL for the TRMNL Android app on GitHub. diff --git a/app/src/main/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStore.kt b/app/src/main/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStore.kt index 8693cbf..b2e83b7 100644 --- a/app/src/main/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStore.kt +++ b/app/src/main/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStore.kt @@ -287,9 +287,9 @@ class TrmnlDeviceConfigDataStore // See: https://github.com/usetrmnl/trmnl-android/issues/240 if (config != null && config.type == TrmnlDeviceType.TRMNL && - config.apiBaseUrl.contains("usetrmnl.com", ignoreCase = true) + config.apiBaseUrl.contains(AppConfig.LEGACY_TRMNL_DOMAIN, ignoreCase = true) ) { - val newUrl = config.apiBaseUrl.replace("usetrmnl.com", "trmnl.com", ignoreCase = true) + val newUrl = config.apiBaseUrl.replace(AppConfig.LEGACY_TRMNL_DOMAIN, AppConfig.TRMNL_DOMAIN, ignoreCase = true) Timber.tag(TAG).i( "Migrating API base URL from ${config.apiBaseUrl} to $newUrl for TRMNL device", ) diff --git a/app/src/test/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStoreTest.kt b/app/src/test/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStoreTest.kt index 8b20528..4109234 100644 --- a/app/src/test/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStoreTest.kt +++ b/app/src/test/java/ink/trmnl/android/data/TrmnlDeviceConfigDataStoreTest.kt @@ -628,19 +628,19 @@ class TrmnlDeviceConfigDataStoreTest { } // ============================================================================ - // Domain Migration Tests (usetrmnl.com → trmnl.com) + // Domain Migration Tests (${AppConfig.LEGACY_TRMNL_DOMAIN} → ${AppConfig.TRMNL_DOMAIN}) // See: https://github.com/usetrmnl/trmnl-android/issues/240 // ============================================================================ @Test fun `deviceConfigFlow migrates usetrmnl_com to trmnl_com for TRMNL device with JSON config`() = runTest { - // Arrange - Save config with old usetrmnl.com URL (JSON storage) + // Arrange - Save config with old ${AppConfig.LEGACY_TRMNL_DOMAIN} URL (JSON storage) val oldConfig = TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://usetrmnl.com/", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}/", refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(oldConfig) @@ -648,16 +648,16 @@ class TrmnlDeviceConfigDataStoreTest { // Act - Read config (should trigger migration) val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() - // Assert - URL should be migrated to trmnl.com + // Assert - URL should be migrated to ${AppConfig.TRMNL_DOMAIN} assertThat(migratedConfig).isNotNull() assertThat(migratedConfig?.type).isEqualTo(TrmnlDeviceType.TRMNL) - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) assertThat(migratedConfig?.apiAccessToken).isEqualTo("test-token") assertThat(migratedConfig?.refreshRateSecs).isEqualTo(600) // Verify migrated config was saved back to DataStore val savedConfig = deviceConfigDataStore.deviceConfigFlow.first() - assertThat(savedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(savedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) } @Test @@ -666,16 +666,16 @@ class TrmnlDeviceConfigDataStoreTest { // Arrange - Save config using legacy individual fields deviceConfigDataStore.saveDeviceType(TrmnlDeviceType.TRMNL) deviceConfigDataStore.saveAccessToken("test-token") - deviceConfigDataStore.saveServerUrl("https://usetrmnl.com/") + deviceConfigDataStore.saveServerUrl("https://${AppConfig.LEGACY_TRMNL_DOMAIN}/") deviceConfigDataStore.saveRefreshRateSeconds(600L) // Act - Read config (should trigger migration) val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() - // Assert - URL should be migrated to trmnl.com + // Assert - URL should be migrated to ${AppConfig.TRMNL_DOMAIN} assertThat(migratedConfig).isNotNull() assertThat(migratedConfig?.type).isEqualTo(TrmnlDeviceType.TRMNL) - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) assertThat(migratedConfig?.apiAccessToken).isEqualTo("test-token") } @@ -696,7 +696,7 @@ class TrmnlDeviceConfigDataStoreTest { val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - Should migrate regardless of case (replacement is always lowercase) - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/api") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://${AppConfig.TRMNL_DOMAIN}/api") } @Test @@ -716,14 +716,14 @@ class TrmnlDeviceConfigDataStoreTest { val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - Should migrate with normalized lowercase domain - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) } @Test fun `deviceConfigFlow does NOT migrate BYOS device with custom usetrmnl_com URL`() = runTest { - // Arrange - BYOS device with custom URL that happens to contain usetrmnl.com - val customUrl = "https://usetrmnl.com.myserver.io/" + // Arrange - BYOS device with custom URL that happens to contain ${AppConfig.LEGACY_TRMNL_DOMAIN} + val customUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}.myserver.io/" val config = TrmnlDeviceConfig( type = TrmnlDeviceType.BYOS, @@ -748,7 +748,7 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.BYOD, apiAccessToken = "test-token", - apiBaseUrl = "https://usetrmnl.com/", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}/", refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config) @@ -757,18 +757,18 @@ class TrmnlDeviceConfigDataStoreTest { val loadedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - Only TRMNL device type gets migrated - assertThat(loadedConfig?.apiBaseUrl).isEqualTo("https://usetrmnl.com/") + assertThat(loadedConfig?.apiBaseUrl).isEqualTo("https://${AppConfig.LEGACY_TRMNL_DOMAIN}/") } @Test fun `deviceConfigFlow does NOT migrate already correct trmnl_com URL`() = runTest { - // Arrange - Already using correct trmnl.com + // Arrange - Already using correct ${AppConfig.TRMNL_DOMAIN} val config = TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://trmnl.com/", + apiBaseUrl = AppConfig.TRMNL_API_SERVER_BASE_URL, refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config) @@ -777,7 +777,7 @@ class TrmnlDeviceConfigDataStoreTest { val loadedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - Should remain unchanged - assertThat(loadedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(loadedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) } @Test @@ -788,7 +788,7 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://usetrmnl.com", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}", refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config) @@ -797,7 +797,7 @@ class TrmnlDeviceConfigDataStoreTest { val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://${AppConfig.TRMNL_DOMAIN}") } @Test @@ -808,7 +808,7 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://usetrmnl.com/api/v1", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}/api/v1", refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config) @@ -817,7 +817,7 @@ class TrmnlDeviceConfigDataStoreTest { val migratedConfig = deviceConfigDataStore.deviceConfigFlow.first() // Assert - Path should be preserved - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/api/v1") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://${AppConfig.TRMNL_DOMAIN}/api/v1") } @Test @@ -828,7 +828,7 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://usetrmnl.com/", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}/", refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config) @@ -839,9 +839,9 @@ class TrmnlDeviceConfigDataStoreTest { val thirdRead = deviceConfigDataStore.deviceConfigFlow.first() // Assert - All reads should return migrated URL - assertThat(firstRead?.apiBaseUrl).isEqualTo("https://trmnl.com/") - assertThat(secondRead?.apiBaseUrl).isEqualTo("https://trmnl.com/") - assertThat(thirdRead?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(firstRead?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) + assertThat(secondRead?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) + assertThat(thirdRead?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) // Verify config is now persistently migrated deviceConfigDataStore.clearAll() @@ -849,12 +849,12 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token", - apiBaseUrl = "https://trmnl.com/", + apiBaseUrl = AppConfig.TRMNL_API_SERVER_BASE_URL, refreshRateSecs = 600, ) deviceConfigDataStore.saveDeviceConfig(config2) val afterReSave = deviceConfigDataStore.deviceConfigFlow.first() - assertThat(afterReSave?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(afterReSave?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) } @Test @@ -865,7 +865,7 @@ class TrmnlDeviceConfigDataStoreTest { TrmnlDeviceConfig( type = TrmnlDeviceType.TRMNL, apiAccessToken = "test-token-12345", - apiBaseUrl = "https://usetrmnl.com/", + apiBaseUrl = "https://${AppConfig.LEGACY_TRMNL_DOMAIN}/", refreshRateSecs = 900, deviceMacId = "aa:bb:cc:dd:ee:ff", isMasterDevice = null, @@ -878,7 +878,7 @@ class TrmnlDeviceConfigDataStoreTest { // Assert - All fields preserved except URL assertThat(migratedConfig?.type).isEqualTo(TrmnlDeviceType.TRMNL) assertThat(migratedConfig?.apiAccessToken).isEqualTo("test-token-12345") - assertThat(migratedConfig?.apiBaseUrl).isEqualTo("https://trmnl.com/") + assertThat(migratedConfig?.apiBaseUrl).isEqualTo(AppConfig.TRMNL_API_SERVER_BASE_URL) assertThat(migratedConfig?.refreshRateSecs).isEqualTo(900) assertThat(migratedConfig?.deviceMacId).isEqualTo("aa:bb:cc:dd:ee:ff") assertThat(migratedConfig?.isMasterDevice).isNull()