This commit is contained in:
2026-04-11 17:32:14 +09:00
parent 2327326cca
commit d0422fafeb
14 changed files with 2297 additions and 130 deletions
@@ -4,6 +4,7 @@ import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.wear.protolayout.ActionBuilders
import androidx.wear.protolayout.ColorBuilders.argb
import androidx.wear.protolayout.DimensionBuilders.dp
@@ -38,7 +39,39 @@ class MainTileService : SuspendingTileService() {
override suspend fun tileRequest(
requestParams: RequestBuilders.TileRequest
) = tile(requestParams, this)
): TileBuilders.Tile {
// 💡 사용자가 방금 누른 버튼의 ID(path)를 가져옵니다.
val clickedPath = requestParams.currentState.lastClickableId
// 눌린 버튼이 있다면 폰(런처)으로 메시지 전송!
if (clickedPath.isNotEmpty()) {
Log.d("MainTileService", "Clicked path: $clickedPath")
Wearable.getNodeClient(this).connectedNodes.addOnSuccessListener { nodes ->
for (node in nodes) {
Wearable.getMessageClient(this).sendMessage(node.id, clickedPath, null)
}
}
}
// 타일 UI 렌더링
val singleTileTimeline = TimelineBuilders.Timeline.Builder()
.addTimelineEntry(
TimelineBuilders.TimelineEntry.Builder()
.setLayout(
LayoutElementBuilders.Layout.Builder()
.setRoot(tileLayout(requestParams, this))
.build()
)
.build()
)
.build()
return TileBuilders.Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(singleTileTimeline)
.build()
}
}
private fun resources(
@@ -73,57 +106,56 @@ private fun tile(
private fun tileLayout(requestParams: RequestBuilders.TileRequest, context: Context): LayoutElementBuilders.LayoutElement {
fun createNavButton(label: String, path: String,x : Float, y :Float): LayoutElementBuilders.LayoutElement {
// 리시버를 실행하기 위한 PendingIntent 생성
val intent = Intent(context, TileActionReceiver::class.java).apply {
putExtra("path", path)
}
val pendingIntent = PendingIntent.getBroadcast(
context, path.hashCode(), intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 버튼 생성 함수 (크기를 48dp로 살짝 줄여서 화면에 쏙 들어가게 맞춤)
fun createNavButton(label: String, path: String): LayoutElementBuilders.LayoutElement {
return LayoutElementBuilders.Box.Builder()
.setModifiers(ModifiersBuilders.Modifiers.Builder()
.setClickable(ModifiersBuilders.Clickable.Builder()
.setOnClick(ActionBuilders.LaunchAction.Builder()
.setAndroidActivity(ActionBuilders.AndroidActivity.Builder()
.setPackageName(context.packageName)
.setClassName(TileActionReceiver::class.java.name) // 리시버 호출
.build())
.build())
.build())
.setTransformation(ModifiersBuilders.Transformation.Builder()
// 방향에 따라 x, y 좌표 조절 (상: 0,-45 / 하: 0,45 / 좌: -45,0 / 우: 45,0)
.setTranslationX(dp(x))
.setTranslationY(dp(y))
.setId(path)
.setOnClick(ActionBuilders.LoadAction.Builder().build())
.build())
.setBackground(ModifiersBuilders.Background.Builder()
.setColor(argb(0xFF303030.toInt()))
.setCorner(ModifiersBuilders.Corner.Builder().setRadius(dp(15f)).build())
.setCorner(ModifiersBuilders.Corner.Builder().setRadius(dp(24f)).build()) // 원형에 가깝게
.build())
.build())
.setWidth(dp(56f)).setHeight(dp(56f))
.addContent(Text.Builder(context, label).build())
.setWidth(dp(48f)).setHeight(dp(48f))
.addContent(
Text.Builder(context, label)
.setTypography(Typography.TYPOGRAPHY_CAPTION2) // 글자 크기 최적화
.setColor(argb(0xFFFFFFFF.toInt()))
.build()
)
.build()
}
return PrimaryLayout.Builder(requestParams.deviceConfiguration)
.setContent(
LayoutElementBuilders.Box.Builder()
// 상 (UP): X는 그대로, Y만 위로(-45dp)
.addContent(createNavButton("UP", "/gesture/up", 0f, -50f))
// 1층: 제일 위에 UP 버튼 하나만
val topRow = LayoutElementBuilders.Row.Builder()
.addContent(createNavButton("UP", "/gesture/up"))
.build()
// 하 (DOWN): X는 그대로, Y만 아래로(+50dp)
.addContent(createNavButton("DOWN", "/gesture/down", 0f, 50f))
// 2층: 중간에 LEFT, 빈 공간, RIGHT 배치
val middleRow = LayoutElementBuilders.Row.Builder()
.addContent(createNavButton("LEFT", "/gesture/left"))
// 좌우 버튼 사이의 널찍한 빈 공간 (UP/DOWN 버튼이 들어갈 간격)
.addContent(LayoutElementBuilders.Spacer.Builder().setWidth(dp(56f)).build())
.addContent(createNavButton("RIGHT", "/gesture/right"))
.build()
// 좌 (LEFT): X를 왼쪽으로(-50dp), Y는 그대로
.addContent(createNavButton("LEFT", "/gesture/left", -50f, 0f))
// 3층: 제일 아래에 DOWN 버튼 하나만
val bottomRow = LayoutElementBuilders.Row.Builder()
.addContent(createNavButton("DOWN", "/gesture/down"))
.build()
// 우 (RIGHT): X를 오른쪽으로(+50dp), Y는 그대로
.addContent(createNavButton("RIGHT", "/gesture/right", 50f, 0f))
.build()
).build()
// 전체를 세로로 정렬하여 합체
return LayoutElementBuilders.Column.Builder()
.setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER) // 가운데 정렬 필수
.addContent(topRow)
.addContent(LayoutElementBuilders.Spacer.Builder().setHeight(dp(8f)).build()) // 1~2층 간격
.addContent(middleRow)
.addContent(LayoutElementBuilders.Spacer.Builder().setHeight(dp(8f)).build()) // 2~3층 간격
.addContent(bottomRow)
.build()
}