From decc2cbb315192cf41d2a5b9085b3acd1526c8a7 Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 18 Jun 2026 00:11:28 +0900 Subject: [PATCH] =?UTF-8?q?feat(creator):=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=ED=8C=9D=EC=97=85=20UI=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../live/ui/CreatorChannelLiveSortPopup.kt | 105 ++++++++++++++++++ .../bg_creator_channel_live_sort_popup.xml | 8 ++ .../bg_creator_channel_live_sort_selected.xml | 4 + .../view_creator_channel_live_sort_menu.xml | 19 ++++ 4 files changed, 136 insertions(+) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt create mode 100644 app/src/main/res/drawable/bg_creator_channel_live_sort_popup.xml create mode 100644 app/src/main/res/drawable/bg_creator_channel_live_sort_selected.xml create mode 100644 app/src/main/res/layout/view_creator_channel_live_sort_menu.xml diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt new file mode 100644 index 00000000..24dddd46 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt @@ -0,0 +1,105 @@ +package kr.co.vividnext.sodalive.v2.creator.channel.live.ui + +import android.graphics.Color +import android.graphics.Rect +import android.graphics.Outline +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.PopupWindow +import android.widget.TextView +import android.widget.FrameLayout +import android.view.ViewOutlineProvider +import androidx.core.graphics.drawable.toDrawable +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.v2.common.data.ContentSort +import kr.co.vividnext.sodalive.v2.creator.channel.live.model.toSortOptionUiModel + +class CreatorChannelLiveSortPopup( + private val anchor: View, + private val selectedSort: ContentSort, + private val onSortSelected: (ContentSort) -> Unit +) { + + private val popupWindow: PopupWindow = PopupWindow(anchor.context).apply { + contentView = createContentView() + width = ViewGroup.LayoutParams.WRAP_CONTENT + height = ViewGroup.LayoutParams.WRAP_CONTENT + isOutsideTouchable = true + isFocusable = true + setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) + } + + fun show() { + val content = popupWindow.contentView + content.measure( + View.MeasureSpec.makeMeasureSpec(anchor.rootView.width, View.MeasureSpec.AT_MOST), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + popupWindow.showAsDropDown(anchor, calculateHorizontalOffset(content.measuredWidth), 0) + } + + fun dismiss() { + popupWindow.dismiss() + } + + private fun createContentView(): View { + val root = FrameLayout(anchor.context) + val view = LayoutInflater.from(anchor.context).inflate( + R.layout.view_creator_channel_live_sort_menu, + root, + false + ) + view.clipToOutline = true + view.outlineProvider = object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + outline.setRoundRect(0, 0, view.width, view.height, view.resources.getDimension(R.dimen.radius_14)) + } + } + val container = view.findViewById(R.id.layout_creator_channel_live_sort_options) + val sample = view.findViewById(R.id.tv_creator_channel_live_sort_option_sample) + container.removeView(sample) + + ContentSort.entries.map { it.toSortOptionUiModel(selectedSort) }.forEach { option -> + val row = TextView(anchor.context).apply { + layoutParams = LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + typeface = sample.typeface + includeFontPadding = false + setPadding(sample.paddingStart, sample.paddingTop, sample.paddingEnd, sample.paddingBottom) + setText(option.labelResId) + setTextColor(sample.currentTextColor) + textSize = 16f + if (option.isSelected) { + setBackgroundResource(R.drawable.bg_creator_channel_live_sort_selected) + } + setOnClickListener { + if (option.sort != selectedSort) { + onSortSelected(option.sort) + } + dismiss() + } + } + container.addView(row) + } + + return view + } + + private fun calculateHorizontalOffset(popupWidth: Int): Int { + val visibleDisplayFrame = Rect() + anchor.rootView.getWindowVisibleDisplayFrame(visibleDisplayFrame) + + val anchorLocation = IntArray(2) + anchor.getLocationOnScreen(anchorLocation) + val popupRight = anchorLocation[0] + popupWidth + return if (popupRight > visibleDisplayFrame.right) { + visibleDisplayFrame.right - popupRight + } else { + 0 + } + } +} diff --git a/app/src/main/res/drawable/bg_creator_channel_live_sort_popup.xml b/app/src/main/res/drawable/bg_creator_channel_live_sort_popup.xml new file mode 100644 index 00000000..769e379c --- /dev/null +++ b/app/src/main/res/drawable/bg_creator_channel_live_sort_popup.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_creator_channel_live_sort_selected.xml b/app/src/main/res/drawable/bg_creator_channel_live_sort_selected.xml new file mode 100644 index 00000000..9c8c4eca --- /dev/null +++ b/app/src/main/res/drawable/bg_creator_channel_live_sort_selected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/layout/view_creator_channel_live_sort_menu.xml b/app/src/main/res/layout/view_creator_channel_live_sort_menu.xml new file mode 100644 index 00000000..59144aac --- /dev/null +++ b/app/src/main/res/layout/view_creator_channel_live_sort_menu.xml @@ -0,0 +1,19 @@ + + + + +