Skip to content

Commit

Permalink
Use Android Studio Tile previews (#1977)
Browse files Browse the repository at this point in the history
  • Loading branch information
yschimke authored Feb 20, 2024
1 parent f6cf2d3 commit 71688da
Show file tree
Hide file tree
Showing 18 changed files with 115 additions and 512 deletions.
14 changes: 9 additions & 5 deletions compose-tools/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,15 @@ package com.google.android.horologist.compose.tools {
}

public final class TilePreviewKt {
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void LayoutElementPreview(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement element, optional @ColorInt int windowBackgroundColor, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.ResourceBuilders.Resources.Builder,kotlin.Unit> tileResourcesFn);
method @androidx.compose.runtime.Composable public static void LayoutRootPreview(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement root, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.ResourceBuilders.Resources.Builder,kotlin.Unit> tileResourcesFn);
method @androidx.compose.runtime.Composable public static <T, R> void TileLayoutPreview(T state, R resourceState, com.google.android.horologist.tiles.render.TileLayoutRenderer<T,R> renderer);
method @androidx.compose.runtime.Composable public static void TilePreview(androidx.wear.tiles.TileBuilders.Tile tile, androidx.wear.protolayout.ResourceBuilders.Resources tileResources, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.StateBuilders.State,androidx.wear.tiles.TileBuilders.Tile>? onLoadAction);
method public static androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters buildDeviceParameters(android.content.res.Resources resources);
method @Deprecated @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void LayoutElementPreview(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement element, optional @ColorInt int windowBackgroundColor, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.ResourceBuilders.Resources.Builder,kotlin.Unit> tileResourcesFn);
method @Deprecated @androidx.compose.runtime.Composable public static void LayoutRootPreview(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement root, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.ResourceBuilders.Resources.Builder,kotlin.Unit> tileResourcesFn);
method @Deprecated @androidx.compose.runtime.Composable public static <T, R> void TileLayoutPreview(T state, R resourceState, com.google.android.horologist.tiles.render.TileLayoutRenderer<T,R> renderer);
method @Deprecated @androidx.compose.runtime.Composable public static void TilePreview(androidx.wear.tiles.TileBuilders.Tile tile, androidx.wear.protolayout.ResourceBuilders.Resources tileResources, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.StateBuilders.State,androidx.wear.tiles.TileBuilders.Tile>? onLoadAction);
method @Deprecated public static androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters buildDeviceParameters(android.content.res.Resources resources);
}

public final class TileRendererPreviewDataKt {
method @androidx.compose.runtime.Composable public static <T, R> androidx.wear.tiles.tooling.preview.TilePreviewData tileRendererPreviewData(com.google.android.horologist.tiles.render.TileLayoutRenderer<T,R> renderer, T tileState, R resourceState);
}

public final class TypographyKt {
Expand Down
2 changes: 2 additions & 0 deletions compose-tools/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ dependencies {
implementation(libs.androidx.wear.tooling.preview)
implementation(libs.kotlinx.coroutines.guava)
api(libs.wearcompose.tooling)
implementation(libs.androidx.wear.tiles.tooling.preview)

debugImplementation(libs.compose.ui.tooling)
debugImplementation(libs.compose.ui.test.manifest)
debugImplementation(libs.androidx.wear.tiles.tooling)
}

apply(plugin = "com.vanniktech.maven.publish")
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

@file:Suppress("DEPRECATION")

package com.google.android.horologist.compose.tools

import android.content.res.Resources
Expand Down Expand Up @@ -57,6 +59,7 @@ import kotlin.math.roundToInt
* Any bitmaps should be preloaded from test resources and passed in via [resourceState] as
* Bitmap or ImageResource.
*/
@Deprecated("Use androidx.wear.tiles.tooling.preview")
@Composable
public fun <T, R> TileLayoutPreview(state: T, resourceState: R, renderer: TileLayoutRenderer<T, R>) {
val context = LocalContext.current
Expand All @@ -79,6 +82,7 @@ public fun <T, R> TileLayoutPreview(state: T, resourceState: R, renderer: TileLa
* Preview a Tile by providing the final proto representation of tiles and resources. It's possible
* to provide an updated Tile representation whenever a load action is triggered.
*/
@Deprecated("Use androidx.wear.tiles.tooling.preview")
@Composable
public fun TilePreview(
tile: TileBuilders.Tile,
Expand Down Expand Up @@ -133,6 +137,7 @@ private fun TileRenderer.preview(
*/
@ExperimentalHorologistApi
@Composable
@Deprecated("Use androidx.wear.tiles.tooling.preview")
public fun LayoutElementPreview(
element: LayoutElement,
@ColorInt windowBackgroundColor: Int = Color.DKGRAY,
Expand Down Expand Up @@ -160,6 +165,7 @@ public fun LayoutElementPreview(
* Preview a root layout component such as a PrimaryLayout, that is full screen.
*/
@Composable
@Deprecated("Use androidx.wear.tiles.tooling.preview")
public fun LayoutRootPreview(
root: LayoutElement,
tileResourcesFn: ResourceBuilders.Resources.Builder.() -> Unit = {},
Expand Down Expand Up @@ -195,6 +201,7 @@ private fun resourceParams(resources: Resources, version: String) =
RequestBuilders.ResourcesRequest.Builder().setDeviceConfiguration(buildDeviceParameters(resources))
.setVersion(version).build()

@Deprecated("Use androidx.wear.tiles.tooling.preview")
public fun buildDeviceParameters(resources: Resources): DeviceParametersBuilders.DeviceParameters {
val displayMetrics: DisplayMetrics = resources.displayMetrics
val isScreenRound: Boolean = resources.configuration.isScreenRound
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.horologist.compose.tools

import androidx.compose.runtime.Composable
import androidx.wear.tiles.tooling.preview.TilePreviewData
import com.google.android.horologist.tiles.render.TileLayoutRenderer

@Composable
public fun <T, R> tileRendererPreviewData(
renderer: TileLayoutRenderer<T, R>,
tileState: T,
resourceState: R,
): TilePreviewData = TilePreviewData(
onTileResourceRequest = { resourcesRequest ->
with(renderer) {
produceRequestedResources(resourceState, resourcesRequest)
}
},
) { tileRequest ->
renderer.renderTimeline(
tileState,
tileRequest,
)
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ room = "2.6.1"
runtimeTracing = "1.0.0-beta01"
snapshot-android = "1.0.4"
spotless = "6.25.0"
tiles-tooling-preview = "1.3.0-alpha04"
truth = "1.4.0"
wearcompose = "1.4.0-alpha02"
wearToolingPreview = "1.0.0"
Expand Down Expand Up @@ -130,6 +131,8 @@ androidx-wear-remote-interactions = { module = "androidx.wear:wear-remote-intera
androidx-wear-tiles = { module = "androidx.wear.tiles:tiles", version.ref = "androidxtiles" }
androidx-wear-tiles-renderer = { module = "androidx.wear.tiles:tiles-renderer", version.ref = "androidxtiles" }
androidx-wear-tiles-testing = { module = "androidx.wear.tiles:tiles-testing", version.ref = "androidxtiles" }
androidx-wear-tiles-tooling-preview = { module = "androidx.wear.tiles:tiles-tooling-preview", version.ref = "tiles-tooling-preview" }
androidx-wear-tiles-tooling = { module = "androidx.wear.tiles:tiles-tooling", version.ref = "tiles-tooling-preview" }
androidx-wear-tooling-preview = { module = "androidx.wear:wear-tooling-preview", version.ref = "wearToolingPreview" }
androidx-work-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "androidxWork" }
androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidxWork" }
Expand Down
2 changes: 2 additions & 0 deletions media/sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ dependencies {
debugImplementation(projects.composeTools)
releaseCompileOnly(projects.composeTools)
add("benchmarkCompileOnly", projects.composeTools)
debugImplementation(libs.androidx.wear.tiles.tooling.preview)
debugImplementation(libs.androidx.wear.tiles.tooling)

testImplementation(libs.junit)
testImplementation(libs.truth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@

package com.google.android.horologist.mediasample.data.service.tile

import android.content.Context
import android.graphics.BitmapFactory
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.wear.compose.ui.tooling.preview.WearPreviewDevices
import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales
import androidx.wear.protolayout.ActionBuilders
import androidx.wear.protolayout.ActionBuilders.AndroidActivity
import androidx.wear.protolayout.ResourceBuilders.Resources
import androidx.wear.tiles.RequestBuilders.ResourcesRequest
import androidx.wear.tiles.RequestBuilders.TileRequest
import androidx.wear.tiles.TileBuilders.Tile
import androidx.wear.tiles.tooling.preview.Preview
import androidx.wear.tiles.tooling.preview.TilePreviewData
import androidx.wear.tooling.preview.devices.WearDevices
import coil.ImageLoader
import com.google.android.horologist.compose.tools.TileLayoutPreview
import com.google.android.horologist.compose.tools.tileRendererPreviewData
import com.google.android.horologist.media.repository.PlaylistRepository
import com.google.android.horologist.media.ui.tiles.MediaCollectionsTileRenderer
import com.google.android.horologist.media.ui.tiles.toTileColors
Expand Down Expand Up @@ -69,8 +69,7 @@ class MediaCollectionsTileService : SuspendingTileService() {
* Render a Playlist primary button and two chips with direct links to collections.
*/
override suspend fun tileRequest(requestParams: TileRequest): Tile {
val playlists = playlistRepository.getAll()
.first()
val playlists = playlistRepository.getAll().first()

val firstPlaylist = playlists.first()
val firstSong = firstPlaylist.mediaList.first()
Expand Down Expand Up @@ -104,9 +103,7 @@ class MediaCollectionsTileService : SuspendingTileService() {
private fun AndroidActivity.Builder.addStringExtra(key: String, value: String) {
addKeyToExtraMapping(
key,
ActionBuilders.AndroidStringExtra.Builder()
.setValue(value)
.build(),
ActionBuilders.AndroidStringExtra.Builder().setValue(value).build(),
)
}

Expand All @@ -116,24 +113,18 @@ class MediaCollectionsTileService : SuspendingTileService() {
*/
private fun appLauncher(
extrasBuilder: AndroidActivity.Builder.() -> Unit = {},
) = ActionBuilders.LaunchAction.Builder()
.setAndroidActivity(
AndroidActivity.Builder()
.setClassName(MediaActivity::class.java.name)
.setPackageName(this.packageName)
.apply {
extrasBuilder()
}
.build(),
)
.build()
) = ActionBuilders.LaunchAction.Builder().setAndroidActivity(
AndroidActivity.Builder().setClassName(MediaActivity::class.java.name)
.setPackageName(this.packageName).apply {
extrasBuilder()
}.build(),
).build()

/**
* Show UAMP as AppIcon, and favourites and podcasts icons.
*/
override suspend fun resourcesRequest(requestParams: ResourcesRequest): Resources {
val playlists = playlistRepository.getAll()
.first()
val playlists = playlistRepository.getAll().first()

val firstPlaylist = playlists.first()
val firstSong = firstPlaylist.mediaList.first()
Expand All @@ -156,55 +147,35 @@ class MediaCollectionsTileService : SuspendingTileService() {
}
}

@WearPreviewDevices
@WearPreviewFontScales
@Preview(device = WearDevices.LARGE_ROUND)
@Preview(device = WearDevices.SMALL_ROUND)
@Composable
fun SampleTilePreview() {
val context = LocalContext.current

val action = ActionBuilders.LaunchAction.Builder()
.build()

val tileState = remember {
MediaCollectionsTileRenderer.MediaCollectionsState(
chipName = R.string.sample_playlists,
chipAction = action,
collection1 = MediaCollectionsTileRenderer.MediaCollection(
name = "Kyoto Songs",
artworkId = "s1",
action = action,
),
collection2 = MediaCollectionsTileRenderer.MediaCollection(
name = "Podcasts",
artworkId = "c2",
action = action,
),
)
}

val resourceState = remember {
val kyoto = BitmapFactory.decodeResource(context.resources, R.drawable.kyoto)

MediaCollectionsTileRenderer.ResourceState(
appIcon = com.google.android.horologist.logo.R.drawable.ic_stat_horologist,
images = mapOf(
"s1" to kyoto?.toImageResource(),
"c2" to drawableResToImageResource(R.drawable.ic_baseline_podcasts_24),
),
)
}

val renderer = remember {
MediaCollectionsTileRenderer(
context = context,
materialTheme = UampColors.toTileColors(),
debugResourceMode = BuildConfig.DEBUG,
)
}

TileLayoutPreview(
tileState,
resourceState,
renderer,
)
}
fun SampleTilePreview(context: Context): TilePreviewData = tileRendererPreviewData(
renderer = MediaCollectionsTileRenderer(
context = context,
materialTheme = UampColors.toTileColors(),
debugResourceMode = BuildConfig.DEBUG,
),
tileState = MediaCollectionsTileRenderer.MediaCollectionsState(
chipName = R.string.sample_playlists,
chipAction = ActionBuilders.LaunchAction.Builder().build(),
collection1 = MediaCollectionsTileRenderer.MediaCollection(
name = "Kyoto Songs",
artworkId = "s1",
action = ActionBuilders.LaunchAction.Builder().build(),
),
collection2 = MediaCollectionsTileRenderer.MediaCollection(
name = "Podcasts",
artworkId = "c2",
action = ActionBuilders.LaunchAction.Builder().build(),
),
),
resourceState = MediaCollectionsTileRenderer.ResourceState(
appIcon = com.google.android.horologist.logo.R.drawable.ic_stat_horologist,
images = mapOf(
"s1" to BitmapFactory.decodeResource(context.resources, R.drawable.kyoto)
?.toImageResource(),
"c2" to drawableResToImageResource(R.drawable.ic_baseline_podcasts_24),
),
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public class MediaCollectionsTileRenderer(
override fun Resources.Builder.produceRequestedResources(
resourceState: ResourceState,
deviceParameters: DeviceParameters,
resourceIds: MutableList<String>,
resourceIds: List<String>,
) {
for ((image, imageResource) in resourceState.images) {
if (imageResource != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

@file:Suppress("DEPRECATION")

package com.google.android.horologist.media.ui.tiles

import androidx.compose.runtime.Composable
Expand Down
2 changes: 2 additions & 0 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ dependencies {

debugImplementation(libs.compose.ui.tooling)
debugImplementation(projects.composeTools)
debugImplementation(libs.androidx.wear.tiles.tooling.preview)
debugImplementation(libs.androidx.wear.tiles.tooling)
releaseCompileOnly(projects.composeTools)

testImplementation(libs.junit)
Expand Down
16 changes: 0 additions & 16 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,6 @@
android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/example_tile" />
</service>

<service
android:name="com.google.android.horologist.tile.SampleTileService"
android:description="@string/sample_tile_description"
android:exported="true"
android:icon="@drawable/ic_person"
android:label="@string/tile_sample_label"
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
<intent-filter>
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
</intent-filter>

<meta-data
android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/sample_tile" />
</service>
</application>

</manifest>
Loading

0 comments on commit 71688da

Please sign in to comment.