Skip to content

Commit

Permalink
Refactor RoborazziComposeConfigBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
takahirom committed Dec 5, 2024
1 parent 1a687c4 commit 31ac20b
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
.idea/modules
/.intellijPlatform/
.idea/runConfigurations.xml
.idea/shelf
*.iml
*.ipr
.DS_Store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,52 @@ import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
fun ComposablePreview<AndroidPreviewInfo>.captureRoboImage(
filePath: String,
roborazziOptions: RoborazziOptions = provideRoborazziContext().options,
configBuilder: RoborazziComposeConfigBuilder = this.toRoborazziComposeConfigBuilder()
roborazziComposeConfig: RoborazziComposeConfig = this.toRoborazziComposeConfig()
) {
if (!roborazziOptions.taskType.isEnabled()) return
val composablePreview = this
captureRoboImage(filePath, roborazziOptions, configBuilder) {
captureRoboImage(filePath, roborazziOptions, roborazziComposeConfig) {
composablePreview()
}
}

@ExperimentalRoborazziApi
fun ComposablePreview<AndroidPreviewInfo>.toRoborazziComposeConfigBuilder() =
RoborazziComposeConfigBuilder()
.size(
fun ComposablePreview<AndroidPreviewInfo>.toRoborazziComposeConfig(): RoborazziComposeConfig {
return RoborazziComposeConfig {
size(
widthDp = previewInfo.widthDp,
heightDp = previewInfo.heightDp
)
.background(
background(
showBackground = previewInfo.showBackground,
backgroundColor = previewInfo.backgroundColor
)
.locale(previewInfo.locale)
.uiMode(previewInfo.uiMode)
.previewDevice(previewInfo.device)
.fontScale(previewInfo.fontScale)
locale(previewInfo.locale)
uiMode(previewInfo.uiMode)
previewDevice(previewInfo.device)
fontScale(previewInfo.fontScale)
}
}


@Suppress("UnusedReceiverParameter")
@Deprecated(
message = "Use previewInfo.toRoborazziComposeConfigBuilder().apply(scenario, composeContent) or ComposablePreview<AndroidPreviewInfo>.captureRoboImage() instead",
replaceWith = ReplaceWith("previewInfo.toRoborazziComposeConfigBuilder().apply(scenario, composeContent)"),
message = "Use previewInfo.toRoborazziComposeConfig().apply(scenario, composeContent) or ComposablePreview<AndroidPreviewInfo>.captureRoboImage() instead",
replaceWith = ReplaceWith("previewInfo.toRoborazziComposeConfig().apply(scenario, composeContent)"),
level = DeprecationLevel.ERROR
)
fun ComposablePreview<AndroidPreviewInfo>.applyToRobolectricConfiguration() {
throw UnsupportedOperationException("Use previewInfo.toRoborazziComposeConfigBuilder().apply(scenario, composeContent) or ComposablePreview<AndroidPreviewInfo>.captureRoboImage() instead")
throw UnsupportedOperationException("Use previewInfo.toRoborazziComposeConfig().apply(scenario, composeContent) or ComposablePreview<AndroidPreviewInfo>.captureRoboImage() instead")
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.previewDevice(previewDevice: String) =
with(RoborazziComposePreviewDeviceConfig(previewDevice))
fun RoborazziComposeConfig.Builder.previewDevice(previewDevice: String): RoborazziComposeConfig.Builder {
return add(RoborazziComposePreviewDeviceConfigurator(previewDevice))
}

@ExperimentalRoborazziApi
data class RoborazziComposePreviewDeviceConfig(private val previewDevice: String) :
RoborazziComposeSetupConfig {
data class RoborazziComposePreviewDeviceConfigurator(private val previewDevice: String) :
RoborazziComposeSetupConfigurator {
override fun configure() {
if (previewDevice.isNotBlank()) {
// Requires `io.github.sergio-sastre.ComposablePreviewScanner:android:0.4.0` or later
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fun captureRoboImage(
captureRoboImage(
file = file,
roborazziOptions = roborazziOptions,
configBuilder = RoborazziComposeConfigBuilder(),
roborazziComposeConfig = RoborazziComposeConfig {},
content = content
)
}
Expand All @@ -39,13 +39,13 @@ fun captureRoboImage(
fun captureRoboImage(
filePath: String = DefaultFileNameGenerator.generateFilePath(),
roborazziOptions: RoborazziOptions = provideRoborazziContext().options,
configBuilder: RoborazziComposeConfigBuilder = RoborazziComposeConfigBuilder(),
roborazziComposeConfig: RoborazziComposeConfig = RoborazziComposeConfig {},
content: @Composable () -> Unit,
) {
captureRoboImage(
file = fileWithRecordFilePathStrategy(filePath),
roborazziOptions = roborazziOptions,
configBuilder = configBuilder,
roborazziComposeConfig = roborazziComposeConfig,
content = content
)
}
Expand All @@ -54,13 +54,13 @@ fun captureRoboImage(
fun captureRoboImage(
file: File,
roborazziOptions: RoborazziOptions = provideRoborazziContext().options,
configBuilder: RoborazziComposeConfigBuilder = RoborazziComposeConfigBuilder(),
roborazziComposeConfig: RoborazziComposeConfig = RoborazziComposeConfig {},
content: @Composable () -> Unit,
) {
if (!roborazziOptions.taskType.isEnabled()) return
launchRoborazziTransparentActivity { activityScenario ->
val configuredContent = configBuilder
.configure(activityScenario) {
val configuredContent = roborazziComposeConfig
.configured(activityScenario) {
content()
}
activityScenario.captureRoboImage(file, roborazziOptions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,72 +18,101 @@ import org.robolectric.shadows.ShadowDisplay.getDefaultDisplay
import kotlin.math.roundToInt

@ExperimentalRoborazziApi
interface RoborazziComposeConfig
interface RoborazziComposeConfigurator

@ExperimentalRoborazziApi
interface RoborazziComposeSetupConfig : RoborazziComposeConfig {
interface RoborazziComposeSetupConfigurator : RoborazziComposeConfigurator {
fun configure()
}

@ExperimentalRoborazziApi
interface RoborazziComposeActivityScenarioConfig : RoborazziComposeConfig {
interface RoborazziComposeActivityScenarioConfigurator : RoborazziComposeConfigurator {
fun configureWithActivityScenario(scenario: ActivityScenario<out Activity>)
}

@ExperimentalRoborazziApi
interface RoborazziComposeComposableConfig : RoborazziComposeConfig {
interface RoborazziComposeComposableConfigurator : RoborazziComposeConfigurator {
fun configureWithComposable(content: @Composable () -> Unit): @Composable () -> Unit
}

@ExperimentalRoborazziApi
class RoborazziComposeConfigBuilder {
private val activityScenarioConfigs =
mutableListOf<RoborazziComposeActivityScenarioConfig>()
private val composableConfigs = mutableListOf<RoborazziComposeComposableConfig>()
private val setupConfigs = mutableListOf<RoborazziComposeSetupConfig>()

fun with(config: RoborazziComposeConfig): RoborazziComposeConfigBuilder {
if (config is RoborazziComposeActivityScenarioConfig) {
activityScenarioConfigs.add(config)
}
if (config is RoborazziComposeComposableConfig) {
composableConfigs.add(config)
class RoborazziComposeConfig private constructor(
private val activityScenarioConfigurators: List<RoborazziComposeActivityScenarioConfigurator>,
private val composableConfigurators: List<RoborazziComposeComposableConfigurator>,
private val setupConfigurators: List<RoborazziComposeSetupConfigurator>
) {
class Builder {
private val activityScenarioConfigurators =
mutableListOf<RoborazziComposeActivityScenarioConfigurator>()
private val composableConfigurators = mutableListOf<RoborazziComposeComposableConfigurator>()
private val setupConfigurators = mutableListOf<RoborazziComposeSetupConfigurator>()

fun add(configurator: RoborazziComposeConfigurator): Builder {
if (configurator is RoborazziComposeActivityScenarioConfigurator) {
activityScenarioConfigurators.add(configurator)
}
if (configurator is RoborazziComposeComposableConfigurator) {
composableConfigurators.add(configurator)
}
if (configurator is RoborazziComposeSetupConfigurator) {
setupConfigurators.add(configurator)
}
return this
}
if (config is RoborazziComposeSetupConfig) {
setupConfigs.add(config)

fun build(): RoborazziComposeConfig {
return RoborazziComposeConfig(
activityScenarioConfigurators = activityScenarioConfigurators,
composableConfigurators = composableConfigurators,
setupConfigurators = setupConfigurators
)
}
return this
}

fun builder(): Builder {
return Builder()
.apply {
activityScenarioConfigurators.forEach { add(it) }
composableConfigurators.forEach { add(it) }
setupConfigurators.forEach { add(it) }
}
}

@ExperimentalRoborazziApi
fun configure(
scenario: ActivityScenario<out Activity>,
fun configured(
activityScenario: ActivityScenario<out Activity>,
content: @Composable () -> Unit
): @Composable () -> Unit {
setupConfigs.forEach { it.configure() }
activityScenarioConfigs.forEach { it.configureWithActivityScenario(scenario) }
setupConfigurators.forEach { it.configure() }
activityScenarioConfigurators.forEach { it.configureWithActivityScenario(activityScenario) }
var appliedContent = content
composableConfigs.forEach { config ->
composableConfigurators.forEach { config ->
appliedContent = config.configureWithComposable(appliedContent)
}
return {
appliedContent()
}
}

companion object {
operator fun invoke(block: Builder.() -> Unit): RoborazziComposeConfig {
return Builder().apply(block).build()
}
}
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.size(
fun RoborazziComposeConfig.Builder.size(
widthDp: Int = 0,
heightDp: Int = 0
): RoborazziComposeConfigBuilder {
return with(RoborazziComposeSizeConfig(widthDp, heightDp))
): RoborazziComposeConfig.Builder {
return add(RoborazziComposeSizeConfigurator(widthDp, heightDp))
}

@ExperimentalRoborazziApi
data class RoborazziComposeSizeConfig(val widthDp: Int, val heightDp: Int) :
RoborazziComposeActivityScenarioConfig,
RoborazziComposeComposableConfig {
data class RoborazziComposeSizeConfigurator(val widthDp: Int, val heightDp: Int) :
RoborazziComposeActivityScenarioConfigurator,
RoborazziComposeComposableConfigurator {
override fun configureWithActivityScenario(scenario: ActivityScenario<out Activity>) {
scenario.onActivity { activity ->
activity.setDisplaySize(widthDp = widthDp, heightDp = heightDp)
Expand Down Expand Up @@ -130,18 +159,18 @@ data class RoborazziComposeSizeConfig(val widthDp: Int, val heightDp: Int) :
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.background(
fun RoborazziComposeConfig.Builder.background(
showBackground: Boolean,
backgroundColor: Long = 0L
): RoborazziComposeConfigBuilder {
return with(RoborazziComposeBackgroundConfig(showBackground, backgroundColor))
): RoborazziComposeConfig.Builder {
return add(RoborazziComposeBackgroundConfigurator(showBackground, backgroundColor))
}

@ExperimentalRoborazziApi
data class RoborazziComposeBackgroundConfig(
data class RoborazziComposeBackgroundConfigurator(
private val showBackground: Boolean,
private val backgroundColor: Long
) : RoborazziComposeActivityScenarioConfig {
) : RoborazziComposeActivityScenarioConfigurator {
override fun configureWithActivityScenario(scenario: ActivityScenario<out Activity>) {
when (showBackground) {
false -> {
Expand All @@ -164,13 +193,13 @@ data class RoborazziComposeBackgroundConfig(
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.uiMode(uiMode: Int): RoborazziComposeConfigBuilder {
return with(RoborazziComposeUiModeConfig(uiMode))
fun RoborazziComposeConfig.Builder.uiMode(uiMode: Int): RoborazziComposeConfig.Builder {
return add(RoborazziComposeUiModeConfigurator(uiMode))
}

@ExperimentalRoborazziApi
data class RoborazziComposeUiModeConfig(private val uiMode: Int) :
RoborazziComposeSetupConfig {
data class RoborazziComposeUiModeConfigurator(private val uiMode: Int) :
RoborazziComposeSetupConfigurator {
override fun configure() {
val nightMode =
when (uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
Expand All @@ -182,30 +211,31 @@ data class RoborazziComposeUiModeConfig(private val uiMode: Int) :
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.locale(locale: String): RoborazziComposeConfigBuilder {
return with(RoborazziComposeLocaleConfig(locale))
fun RoborazziComposeConfig.Builder.locale(locale: String): RoborazziComposeConfig.Builder {
return add(RoborazziComposeLocaleConfigurator(locale))
}

@ExperimentalRoborazziApi
data class RoborazziComposeLocaleConfig(private val locale: String) :
RoborazziComposeSetupConfig {
data class RoborazziComposeLocaleConfigurator(private val locale: String) :
RoborazziComposeSetupConfigurator {
override fun configure() {
val localeWithFallback = locale.ifBlank { "en" }
setQualifiers("+$localeWithFallback")
}
}

@ExperimentalRoborazziApi
fun RoborazziComposeConfigBuilder.fontScale(fontScale: Float): RoborazziComposeConfigBuilder {
return with(RoborazziComposeFontScaleConfig(fontScale))
fun RoborazziComposeConfig.Builder.fontScale(fontScale: Float): RoborazziComposeConfig.Builder {
return add(RoborazziComposeFontScaleConfigurator(fontScale))
}

@ExperimentalRoborazziApi
data class RoborazziComposeFontScaleConfig(private val fontScale: Float) :
RoborazziComposeSetupConfig {
data class RoborazziComposeFontScaleConfigurator(private val fontScale: Float) :
RoborazziComposeSetupConfigurator {
init {
require(fontScale > 0) { "fontScale must be greater than 0" }
}

override fun configure() {
setFontScale(fontScale)
}
Expand Down

0 comments on commit 31ac20b

Please sign in to comment.