diff --git a/app/src/main/java/org/fdroid/fdroid/views/repos/RepoPreviewScreen.kt b/app/src/main/java/org/fdroid/fdroid/views/repos/RepoPreviewScreen.kt index 1f65ef343..e8847de09 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/repos/RepoPreviewScreen.kt +++ b/app/src/main/java/org/fdroid/fdroid/views/repos/RepoPreviewScreen.kt @@ -45,6 +45,7 @@ import org.fdroid.fdroid.Utils.getGlideModel import org.fdroid.fdroid.compose.ComposeUtils.FDroidButton import org.fdroid.fdroid.compose.ComposeUtils.FDroidContent import org.fdroid.index.v2.FileV2 +import org.fdroid.repo.FetchResult.IsExistingMirror import org.fdroid.repo.FetchResult.IsExistingRepository import org.fdroid.repo.FetchResult.IsNewMirror import org.fdroid.repo.FetchResult.IsNewRepository @@ -122,6 +123,10 @@ fun RepoPreviewHeader( ) } } + if (state.isMirror) Text( + text = stringResource(R.string.repo_mirror_add_info), + style = MaterialTheme.typography.body2, + ) if (state.canAdd) FDroidButton( text = when (state.fetchResult) { is IsNewRepository -> stringResource(R.string.repo_add_new_title) @@ -129,14 +134,16 @@ fun RepoPreviewHeader( else -> error("Unexpected fetch state: ${state.fetchResult}") }, onClick = onAddRepo, - modifier = Modifier.align(End) - ) else if (state.fetchResult is IsExistingRepository) { - Text( - text = stringResource(R.string.repo_exists), - style = MaterialTheme.typography.body1, - color = MaterialTheme.colors.error, - ) - } + modifier = Modifier.align(End), + ) else Text( + text = when (state.fetchResult) { + is IsExistingRepository -> stringResource(R.string.repo_exists) + is IsExistingMirror -> stringResource(R.string.repo_mirror_exists) + else -> error("Unexpected fetch state: ${state.fetchResult}") + }, + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.error, + ) val description = if (isDevPreview) { LoremIpsum(42).values.joinToString(" ") } else { @@ -233,12 +240,11 @@ fun RepoPreviewScreenFetchingPreview() { @Composable @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 720, heightDp = 360) fun RepoPreviewScreenNewMirrorPreview() { - val address = "https://example.org" - val repo = FDroidApp.createSwapRepo(address, "foo bar") + val repo = FDroidApp.createSwapRepo("https://example.org", "foo bar") FDroidContent { RepoPreviewScreen( PaddingValues(0.dp), - Fetching(address, repo, emptyList(), IsNewMirror(0L)) + Fetching("https://mirror.example.org", repo, emptyList(), IsNewMirror(0L)) ) {} } } @@ -255,3 +261,15 @@ fun RepoPreviewScreenExistingRepoPreview() { ) {} } } + +@Preview +@Composable +fun RepoPreviewScreenExistingMirrorPreview() { + val repo = FDroidApp.createSwapRepo("https://example.org", "foo bar") + FDroidContent { + RepoPreviewScreen( + PaddingValues(0.dp), + Fetching("https://mirror.example.org", repo, emptyList(), IsExistingMirror) + ) {} + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb2162e5e..6838f262e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -223,6 +223,8 @@ This often occurs with apps installed via Google Play or other sources, if they Error connecting to the repository. Archive repositories can not be added directly. Tap the repository in the list and enable the archive there. Could not find repo address in shared text. + This mirror was already added. + The URL you are trying to add is a mirror of an existing repository. Bad fingerprint This is not a valid URL. Ignoring malformed repo URI: %s diff --git a/libs/database/src/main/java/org/fdroid/repo/RepoAdder.kt b/libs/database/src/main/java/org/fdroid/repo/RepoAdder.kt index 5a0b000ed..a808619fe 100644 --- a/libs/database/src/main/java/org/fdroid/repo/RepoAdder.kt +++ b/libs/database/src/main/java/org/fdroid/repo/RepoAdder.kt @@ -62,8 +62,14 @@ public class Fetching( /** * true if the repository can be added (be it as new [Repository] or new mirror). */ - public val canAdd: Boolean = repo != null && - (fetchResult != null && fetchResult !is FetchResult.IsExistingRepository) + public val canAdd: Boolean = repo != null + && fetchResult != null + && fetchResult !is FetchResult.IsExistingRepository + && fetchResult !is FetchResult.IsExistingMirror + + public val isMirror: Boolean = repo != null + && fetchResult != null + && (fetchResult is FetchResult.IsNewMirror || fetchResult is FetchResult.IsExistingMirror) override fun toString(): String { return "Fetching(fetchUrl=$fetchUrl, repo=${repo?.address}, apps=${apps.size}, " + @@ -95,6 +101,7 @@ public sealed class FetchResult { public data class IsNewMirror(internal val existingRepoId: Long) : FetchResult() public data object IsExistingRepository : FetchResult() + public data object IsExistingMirror : FetchResult() } @OptIn(DelicateCoroutinesApi::class) @@ -233,17 +240,15 @@ internal class RepoAdder( return if (existingRepo == null) { FetchResult.IsNewRepository + } else if (existingRepo.address.trimEnd('/') == url) { + FetchResult.IsExistingRepository } else { - val existingMirror = if (existingRepo.address.trimEnd('/') == url) { - url - } else { - existingRepo.mirrors.find { it.url.trimEnd('/') == url } - ?: existingRepo.userMirrors.find { it.trimEnd('/') == url } - } + val existingMirror = existingRepo.mirrors.find { it.url.trimEnd('/') == url } + ?: existingRepo.userMirrors.find { it.trimEnd('/') == url } if (existingMirror == null) { FetchResult.IsNewMirror(existingRepo.repoId) } else { - FetchResult.IsExistingRepository + FetchResult.IsExistingMirror } } } @@ -266,7 +271,8 @@ internal class RepoAdder( ?: throw IllegalStateException("No fetchResult: ${addRepoState.value}") val modifiedRepo: Repository = when (fetchResult) { - is FetchResult.IsExistingRepository -> error("Unexpected result: $fetchResult") + is FetchResult.IsExistingRepository -> error("Repo exists: $fetchResult") + is FetchResult.IsExistingMirror -> error("Mirror exists: $fetchResult") is FetchResult.IsNewRepository -> { // reset the timestamp of the actual repo, // so a following repo update will pick this up @@ -283,7 +289,7 @@ internal class RepoAdder( val repoId = repositoryDao.insert(newRepo) // add user mirror, if URL is not the repo address and not a known mirror if (state.fetchUrl != repo.address.trimEnd('/') && - repo.mirrors.find {state.fetchUrl == it.url.trimEnd('/') } == null + repo.mirrors.find { state.fetchUrl == it.url.trimEnd('/') } == null ) { val userMirrors = listOf(state.fetchUrl) repositoryDao.updateUserMirrors(repoId, userMirrors) diff --git a/libs/database/src/test/java/org/fdroid/repo/RepoAdderTest.kt b/libs/database/src/test/java/org/fdroid/repo/RepoAdderTest.kt index ae1c61fff..d2181cbc6 100644 --- a/libs/database/src/test/java/org/fdroid/repo/RepoAdderTest.kt +++ b/libs/database/src/test/java/org/fdroid/repo/RepoAdderTest.kt @@ -358,8 +358,11 @@ internal class RepoAdderTest { // repo is already in the DB every { repoDao.getRepository(any()) } returns existingRepo - expectMinRepoPreview(repoName, FetchResult.IsExistingRepository, canAdd = false) { - repoAdder.fetchRepository(url = url, proxy = null) + val expectedFetchResult = + if (existingRepo.address == url) FetchResult.IsExistingRepository else FetchResult.IsExistingMirror + + expectMinRepoPreview(repoName, expectedFetchResult, canAdd = false) { + repoAdder.fetchRepository(url = downloadUrl, proxy = null) } assertFailsWith { repoAdder.addFetchedRepository()