Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port ProjectResourceRepository and AppResourceRepository from platform/tools/adt/idea #923

Merged
merged 1 commit into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import app.cash.paparazzi.deprecated.com.android.ide.common.resources.deprecated
import app.cash.paparazzi.deprecated.com.android.io.FolderWrapper
import app.cash.paparazzi.getFieldReflectively
import app.cash.paparazzi.internal.resources.AarSourceResourceRepository
import app.cash.paparazzi.internal.resources.AppResourceRepository
import app.cash.paparazzi.internal.resources.FrameworkResourceRepository
import app.cash.paparazzi.setStaticValue
import com.android.layoutlib.bridge.Bridge
Expand Down Expand Up @@ -74,22 +75,21 @@ internal class Renderer(
languagesToLoad = emptySet(),
useCompiled9Patches = true
)
)

// ResourceRepositoryBridge.New(TODO("Add ModuleResourceRepository"))

val libraryResourceRepositories = environment.libraryResourceDirs.map { dir ->
val resourceDirPath = Paths.get(dir)
AarSourceResourceRepository.create(
resourceDirectoryOrFile = resourceDirPath,
libraryName = resourceDirPath.parent.fileName.name // segment before /res
) to
ResourceRepositoryBridge.New(
AppResourceRepository.create(
localResourceDirectories = environment.localResourceDirs.map { File(it) },
libraryRepositories = environment.libraryResourceDirs.map { dir ->
val resourceDirPath = Paths.get(dir)
AarSourceResourceRepository.create(
resourceDirectoryOrFile = resourceDirPath,
libraryName = resourceDirPath.parent.fileName.name // segment before /res
)
}
)
)
}

// ./gradlew sample:testDebug --tests=app.cash.paparazzi.sample.LaunchViewTest -Papp.cash.paparazzi.new.resource.loading=true
println(libraryResourceRepositories.map { it.origin }.joinToString(separator = "\n"))

TODO("New resource loading coming soon")
}

sessionParamsBuilder = SessionParamsBuilder(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.android.ide.common.rendering.api.SessionParams.Key
import com.android.ide.common.rendering.api.SessionParams.RenderingMode
import com.android.ide.common.resources.ResourceResolver
import com.android.ide.common.resources.ResourceValueMap
import com.android.ide.common.resources.getConfiguredResources
import com.android.layoutlib.bridge.Bridge
import com.android.resources.LayoutDirection
import com.android.resources.ResourceType
Expand Down Expand Up @@ -84,15 +85,24 @@ internal data class SessionParamsBuilder(
ResourceNamespace.ANDROID to
frameworkResources.repository.getConfiguredResources(folderConfiguration)

is New -> TODO()
is New ->
ResourceNamespace.ANDROID to
frameworkResources.repository.getConfiguredResources(folderConfiguration)
.row(ResourceNamespace.ANDROID)
},
when (projectResources) {
*when (projectResources) {
is Legacy -> {
ResourceNamespace.TODO() to
projectResources.repository.getConfiguredResources(folderConfiguration)
arrayOf(
ResourceNamespace.TODO() to
projectResources.repository.getConfiguredResources(folderConfiguration)
)
}

is New -> TODO()
is New ->
projectResources.repository.getConfiguredResources(folderConfiguration)
.rowMap()
.map { (key, value) -> key to value }
.toTypedArray()
}
),
ResourceReference(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package app.cash.paparazzi.internal.resources

import java.io.File

/**
* Ported from: [AppResourceRepository.java](https://cs.android.com/android-studio/platform/tools/adt/idea/+/308d48ccea9508984bce3e120a03ed9a105d4331:android/src/com/android/tools/idea/res/AppResourceRepository.java)
*
* Returns the repository with all non-framework resources available to a given module (in the current variant).
* This includes not just the resources defined in this module, but in any other modules that this module depends
* on, as well as any libraries those modules may depend on (e.g. appcompat).
*
* When a layout is rendered in the layout editor, it is getting resources from the app resource repository:
* it should see all the resources just like the app does.
*/
internal class AppResourceRepository private constructor(
displayName: String,
localResources: List<LocalResourceRepository>,
libraryResources: Collection<AarSourceResourceRepository>
) : MultiResourceRepository("$displayName with modules and libraries") {

init {
setChildren(localResources, libraryResources)
}

companion object {
fun create(
localResourceDirectories: List<File>,
libraryRepositories: Collection<AarSourceResourceRepository>
): AppResourceRepository {
return AppResourceRepository(
displayName = "",
listOf(ProjectResourceRepository.create(localResourceDirectories)),
libraryRepositories
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app.cash.paparazzi.internal.resources

import com.android.ide.common.rendering.api.ResourceNamespace
import java.io.File

/**
* Ported from: [ProjectResourceRepository.java](https://cs.android.com/android-studio/platform/tools/adt/idea/+/c847337ee5caa1d57cb1cb991cfcafaf6c90d0c6:android/src/com/android/tools/idea/res/ProjectResourceRepository.java)
*
* The resource repository for a module along with all its (local) module dependencies.
* The repository doesn't contain resources from AAR dependencies.
*/
internal class ProjectResourceRepository private constructor(
displayName: String,
localResources: List<LocalResourceRepository>
) : MultiResourceRepository("$displayName with modules") {
init {
setChildren(localResources, emptyList())
}

companion object {
fun create(
resourceDirectories: List<File>
): ProjectResourceRepository {
return ProjectResourceRepository(
displayName = "main",
// TODO: need mapOf(package to listOf(resourceDirectory)) for each transitive project module
localResources = listOf(
ModuleResourceRepository.forMainResources(
namespace = getNamespace(namespacing = ResourceNamespacing.DISABLED, packageName = "TODO"),
resourceDirectories = resourceDirectories
)
)
)
}

private fun getNamespace(namespacing: ResourceNamespacing, packageName: String?): ResourceNamespace {
if (namespacing === ResourceNamespacing.DISABLED || packageName == null) {
return ResourceNamespace.RES_AUTO
}
return ResourceNamespace.fromPackageName(packageName)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.cash.paparazzi.internal.resources

enum class ResourceNamespacing {
/**
* Resources are not namespaced.
*/
DISABLED,

/**
* Resources must be namespaced.
*/
REQUIRED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package app.cash.paparazzi.internal.resources

import com.android.ide.common.rendering.api.AttrResourceValue
import com.android.ide.common.rendering.api.AttributeFormat
import com.android.resources.ResourceType
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import java.io.File

class AppResourceRepositoryTest {
@Test
fun test() {
val repository = AppResourceRepository.create(
localResourceDirectories = listOf(File("src/test/resources/folders/res")),
libraryRepositories = listOf(makeAarRepositoryFromExplodedAar("my_aar_lib"))
)

val map = repository.allResources
assertThat(map.size).isEqualTo(44)

assertThat(map[0].name).isEqualTo("slide_in_from_left")
assertThat(map[0].type).isEqualTo(ResourceType.ANIM)
assertThat(map[1].name).isEqualTo("test_animator")
assertThat(map[1].type).isEqualTo(ResourceType.ANIMATOR)

assertThat(map[4].name).isEqualTo("some_attr")
assertThat(map[4].type).isEqualTo(ResourceType.ATTR)
assertThat((map[4].resourceValue as AttrResourceValue).formats).isEqualTo(setOf(AttributeFormat.COLOR))

assertThat(map[43].name).isEqualTo("test_network_security_config")
assertThat(map[43].type).isEqualTo(ResourceType.XML)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ class ModuleResourceRepositoryTest {
)

val map = repository.allResources
assertThat(map.size).isEqualTo(31)

assertThat(map[0].name).isEqualTo("slide_in_from_left")
assertThat(map[0].type).isEqualTo(ResourceType.ANIM)
assertThat(map[1].name).isEqualTo("test_animator")
assertThat(map[1].type).isEqualTo(ResourceType.ANIMATOR)

assertThat(map[30].name).isEqualTo("test_network_security_config")
assertThat(map[30].type).isEqualTo(ResourceType.XML)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package app.cash.paparazzi.internal.resources

import com.android.resources.ResourceType
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import java.io.File

class ProjectResourceRepositoryTest {
@Test
fun test() {
// TODO: need mapOf(package to listOf(resourceDirectory)) for each transitive project module
val repository = ProjectResourceRepository.create(
resourceDirectories = listOf(File("src/test/resources/folders/res"))
)

val map = repository.allResources
assertThat(map.size).isEqualTo(31)

assertThat(map[0].name).isEqualTo("slide_in_from_left")
assertThat(map[0].type).isEqualTo(ResourceType.ANIM)
assertThat(map[1].name).isEqualTo("test_animator")
assertThat(map[1].type).isEqualTo(ResourceType.ANIMATOR)

assertThat(map[30].name).isEqualTo("test_network_security_config")
assertThat(map[30].type).isEqualTo(ResourceType.XML)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ class ResourceFolderRepositoryTest {
)

val map = repository.allResources
map.forEach {
println(it)
}
assertThat(map.size).isEqualTo(31)

// ANIM
Expand Down