diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ecf14c69..a3c5cea9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,6 +23,7 @@ android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Deepr"> diff --git a/app/src/main/java/com/yogeshpaliyal/deepr/DeeprApplication.kt b/app/src/main/java/com/yogeshpaliyal/deepr/DeeprApplication.kt index 338fb4fb..171a227d 100644 --- a/app/src/main/java/com/yogeshpaliyal/deepr/DeeprApplication.kt +++ b/app/src/main/java/com/yogeshpaliyal/deepr/DeeprApplication.kt @@ -97,7 +97,7 @@ class DeeprApplication : Application() { } single { - NetworkRepository(get(), get()) + NetworkRepository(get()) } single { diff --git a/app/src/main/java/com/yogeshpaliyal/deepr/data/NetworkRepository.kt b/app/src/main/java/com/yogeshpaliyal/deepr/data/NetworkRepository.kt index 518aca8c..e4bb6ed7 100644 --- a/app/src/main/java/com/yogeshpaliyal/deepr/data/NetworkRepository.kt +++ b/app/src/main/java/com/yogeshpaliyal/deepr/data/NetworkRepository.kt @@ -2,17 +2,23 @@ package com.yogeshpaliyal.deepr.data import com.yogeshpaliyal.deepr.util.normalizeLink import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText class NetworkRepository( - val httpClient: HttpClient, val httpParser: HtmlParser, ) { + val httpClient: HttpClient by lazy { + HttpClient(CIO) + } + suspend fun getLinkInfo(url: String): Result { val normalizedUrl = normalizeLink(url) try { - val response = httpClient.get(normalizedUrl) + val response = + httpClient.get(normalizedUrl) { + } if (response.status.value != 200) { return Result.failure(Exception("Failed to fetch data from $normalizedUrl, status code: ${response.status.value}")) } diff --git a/app/src/main/java/com/yogeshpaliyal/deepr/ui/screens/home/HomeBottomContent.kt b/app/src/main/java/com/yogeshpaliyal/deepr/ui/screens/home/HomeBottomContent.kt index 987dc6af..fdc9b999 100644 --- a/app/src/main/java/com/yogeshpaliyal/deepr/ui/screens/home/HomeBottomContent.kt +++ b/app/src/main/java/com/yogeshpaliyal/deepr/ui/screens/home/HomeBottomContent.kt @@ -256,18 +256,34 @@ fun HomeBottomContent( Spacer(modifier = Modifier.height(8.dp)) if (deeprInfo.thumbnail.isNotEmpty() && isThumbnailEnable) { - AsyncImage( - model = deeprInfo.thumbnail, - contentDescription = deeprInfo.name, - modifier = - Modifier - .fillMaxWidth() - .aspectRatio(1.91f) - .background(MaterialTheme.colorScheme.surfaceVariant), - placeholder = null, - error = null, - contentScale = ContentScale.Crop, - ) + Column { + AsyncImage( + model = deeprInfo.thumbnail, + contentDescription = deeprInfo.name, + modifier = + Modifier + .fillMaxWidth() + .aspectRatio(1.91f) + .background(MaterialTheme.colorScheme.surfaceVariant), + placeholder = null, + error = null, + contentScale = ContentScale.Crop, + ) + Spacer(modifier = Modifier.height(8.dp)) + OutlinedButton( + onClick = { + deeprInfo = deeprInfo.copy(thumbnail = "") + }, + modifier = Modifier.fillMaxWidth(), + ) { + Icon( + imageVector = TablerIcons.X, + contentDescription = stringResource(R.string.remove_thumbnail), + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(stringResource(R.string.remove_thumbnail)) + } + } } Spacer(modifier = Modifier.height(8.dp)) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index add0f234..8b4db7e8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,7 +20,7 @@ Add to favourites Remove from favourites Add Link - Fetch name from link + Fetch meta from link Create Tag New tag (Optional) No links saved yet @@ -33,6 +33,7 @@ Try selecting different tags or clear filters. No favourites in selected tags Mark links with these tags as favourites or try different tags. + Remove thumbnail More options diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..8b18cdfa --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/yogeshpaliyal/deepr/data/NetworkRepositoryTest.kt b/app/src/test/java/com/yogeshpaliyal/deepr/data/NetworkRepositoryTest.kt index fd325eec..bc9e5996 100644 --- a/app/src/test/java/com/yogeshpaliyal/deepr/data/NetworkRepositoryTest.kt +++ b/app/src/test/java/com/yogeshpaliyal/deepr/data/NetworkRepositoryTest.kt @@ -3,6 +3,7 @@ package com.yogeshpaliyal.deepr.data import io.ktor.client.HttpClient import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.respond +import io.ktor.client.plugins.UserAgent import io.ktor.http.HttpStatusCode import io.ktor.http.headersOf import kotlinx.coroutines.test.runTest @@ -152,4 +153,39 @@ class NetworkRepositoryTest { assertEquals("Test Title", linkInfo?.title) assertEquals("https://example.com/image.jpg", linkInfo?.image) } + + @Test + fun getLinkInfo_sendsUserAgentHeader() = + runTest { + // Create a mock HTTP client that captures the User-Agent header + var receivedUserAgent: String? = null + val mockEngine = + MockEngine { request -> + receivedUserAgent = request.headers["User-Agent"] + respond( + content = mockHtmlContent, + status = HttpStatusCode.OK, + headers = headersOf("Content-Type", "text/html"), + ) + } + + val httpClient = + HttpClient(mockEngine) { + install(UserAgent) { + agent = + "Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36" + } + } + val htmlParser = HtmlParser() + val repository = NetworkRepository(httpClient, htmlParser) + + val result = repository.getLinkInfo("example.com") + + // Verify the User-Agent header was sent + assertTrue(result.isSuccess) + assertEquals( + "Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36", + receivedUserAgent, + ) + } }