diff --git a/VisualNovel/app/src/main/assets/uitoken/token_sys.json b/VisualNovel/app/src/main/assets/uitoken/token_sys.json index 6593dc7..e457763 100644 --- a/VisualNovel/app/src/main/assets/uitoken/token_sys.json +++ b/VisualNovel/app/src/main/assets/uitoken/token_sys.json @@ -197,6 +197,8 @@ "border.divider": "$glo.border.half", "border.s": "$glo.border.1", "border.m": "$glo.border.2", - "border.l": "$glo.border.4" + "border.l": "$glo.border.4", + + "color.chat.setting.item.bg": "$glo.color.chat.setting.item.bg" } diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ChatActivity.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ChatActivity.kt index 898fe6d..98dbfc9 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ChatActivity.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ChatActivity.kt @@ -4,7 +4,6 @@ package com.remax.visualnovel.ui.chat import android.graphics.Point import androidx.activity.viewModels import androidx.core.view.GravityCompat -import androidx.core.view.marginTop import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import com.alibaba.android.arouter.facade.annotation.Route @@ -18,14 +17,12 @@ import com.remax.visualnovel.utils.Routers import com.remax.visualnovel.utils.StatusBarUtils import com.pengxr.modular.eventbus.generated.events.EventDefineOfUserEvents import com.remax.visualnovel.R -import com.remax.visualnovel.databinding.ActivityActorChat2Binding import com.remax.visualnovel.databinding.ActivityActorChatBinding import com.remax.visualnovel.entity.request.ChatSetting import com.remax.visualnovel.event.model.OnLoginEvent import com.remax.visualnovel.extension.countDownCoroutines import com.remax.visualnovel.extension.launchAndLoadingCollect import com.remax.visualnovel.extension.launchWithRequest -import com.remax.visualnovel.extension.setMargin import com.remax.visualnovel.extension.toast import com.remax.visualnovel.manager.nim.NimManager import com.remax.visualnovel.ui.chat.setting.model.ChatModelDialog @@ -39,7 +36,7 @@ import kotlin.getValue @AndroidEntryPoint @Route(path = Routers.CHAT) -class ChatActivity : BaseBindingActivity() { +class ChatActivity : BaseBindingActivity() { private val chatViewModel by viewModels() private val mRecordAssist = RecordAssist() @@ -52,7 +49,7 @@ class ChatActivity : BaseBindingActivity() { StatusBarUtils.setStatusBarAndNavBarIsLight(this, false) StatusBarUtils.setTransparent(this) - binding.root.setMargin(topMargin = StatusBarUtils.statusBarHeight) + binding.root.setPadding(binding.root.paddingLeft, binding.root.paddingTop + StatusBarUtils.statusBarHeight, binding.root.paddingRight, binding.root.paddingBottom) binding.toolbar.addRightIcon(R.mipmap.chat_title_setting) { binding.drawerMenu.openDrawer(GravityCompat.END) } diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/ChatSettingView.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/ChatSettingView.kt index 59fc06e..517cb88 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/ChatSettingView.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/ChatSettingView.kt @@ -14,12 +14,11 @@ class ChatSettingView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { - private lateinit var mBinding: LayoutChatMenuViewBinding + private var mBinding = LayoutChatMenuViewBinding.inflate(LayoutInflater.from(context), this, true) init { - mBinding = LayoutChatMenuViewBinding.inflate(LayoutInflater.from(context)) - LayoutInflater.from(context).inflate(R.layout.base_toolbar_layout, this, true) + } } diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/ExpandSelectView.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/ExpandSelectView.kt new file mode 100644 index 0000000..ab07aa4 --- /dev/null +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/ExpandSelectView.kt @@ -0,0 +1,216 @@ +package com.remax.visualnovel.ui.chat.ui.expandableSelector + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.GradientDrawable +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.animation.AccelerateDecelerateInterpolator +import android.widget.LinearLayout +import android.widget.TextView +import com.remax.visualnovel.R +import com.remax.visualnovel.databinding.LayoutExpandSelectViewBinding + + +class ExpandSelectView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private lateinit var mBinding: LayoutExpandSelectViewBinding + + private var isExpanded = false + private var animationDuration = 300 + private var items: List = emptyList() + private var itemSelectedListener: OnItemSelectedListener? = null + + init { + initView(context, attrs) + } + + private fun initView(context: Context, attrs: AttributeSet?) { + mBinding = LayoutExpandSelectViewBinding.inflate(LayoutInflater.from(context)) + setupAttributes(attrs) + setupClickListeners() + } + + private fun setupAttributes(attrs: AttributeSet?) { + attrs?.let { + val typedArray = context.obtainStyledAttributes(it, R.styleable.ExpandableSelector) + val title = typedArray.getString(R.styleable.ExpandableSelector_titleText) + title?.let { mBinding.titleText.text = it } + animationDuration = typedArray.getInt(R.styleable.ExpandableSelector_animationDuration, 300) + typedArray.recycle() + } + } + + private fun setupClickListeners() { + mBinding.titleLayout.setOnClickListener { toggle() } + } + + + fun setTitleIcon(resId: Int) { + mBinding.icon.setImageResource(resId) + } + + fun setTitleText(title: String) { + mBinding.titleText.text = title + } + + fun setPopItems(newItems: List) { + items = newItems + updateItemsView() + } + + + private fun updateItemsView() { + mBinding.itemsContainer.removeAllViews() + + items.forEachIndexed { index, item -> + val itemView = createItemView(item, index) + mBinding.itemsContainer.addView(itemView) + + if (index < items.size - 1) { + addDivider() + } + } + } + + private fun createItemView(item: SelectorItem, position: Int): View { + val itemView = LayoutInflater.from(context) + .inflate(R.layout.layout_expand_view_item, mBinding.itemsContainer, false) + + val colorIndicator = itemView.findViewById(R.id.colorIndicator) + val itemName = itemView.findViewById(R.id.itemName) + val itemDesc = itemView.findViewById(R.id.itemDesc) + val pointsInfo = itemView.findViewById(R.id.pointsInfo) + val recommendedTag = itemView.findViewById(R.id.recommendedTag) + val selectedDot = itemView.findViewById(R.id.selectedDot) + + // 设置颜色指示器 + (colorIndicator.background as? GradientDrawable)?.setColor(item.color) + + itemName.text = item.name + itemDesc.text = item.description + pointsInfo.text = item.pointsInfo + + // 显示推荐标签 + recommendedTag.visibility = if (item.isRecommended) View.VISIBLE else View.GONE + + // 显示选中圆点 + selectedDot.visibility = if (item.isSelected) View.VISIBLE else View.GONE + + // 设置点击事件 + itemView.setOnClickListener { + selectItem(position) + itemSelectedListener?.onItemSelected(position, item) + } + + return itemView + } + + private fun addDivider() { + val divider = View(context).apply { + layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 1).apply { + setBackgroundColor(Color.parseColor("#EEEEEE")) + } + } + mBinding.itemsContainer.addView(divider) + } + + + fun selectItem(position: Int) { + items.forEachIndexed { index, item -> + item.isSelected = index == position + } + updateItemsView() + + if (position in items.indices) { + mBinding.titleText.text = items[position].name + } + + collapse() + } + + + fun toggle() { + if (isExpanded) collapse() else expand() + } + + fun expand() { + if (isExpanded) return + + isExpanded = true + mBinding.itemsContainer.visibility = View.VISIBLE + animateArrow(0f, 180f) + // param height anim + val animator = ValueAnimator.ofInt(0, getItemsHeight()) + animator.duration = animationDuration.toLong() + animator.interpolator = AccelerateDecelerateInterpolator() + animator.addUpdateListener { animation -> + val value = animation.animatedValue as Int + val params = mBinding.itemsContainer.layoutParams + params.height = value + mBinding.itemsContainer.layoutParams = params + } + animator.start() + } + + + fun collapse() { + if (!isExpanded) return + + isExpanded = false + animateArrow(180f, 0f) + // param height anim + val animator = ValueAnimator.ofInt(getItemsHeight(), 0) + animator.duration = animationDuration.toLong() + animator.interpolator = AccelerateDecelerateInterpolator() + animator.addUpdateListener { animation -> + val value = animation.animatedValue as Int + val params = mBinding.itemsContainer.layoutParams + params.height = value + mBinding.itemsContainer.layoutParams = params + } + animator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + mBinding.itemsContainer.visibility = View.GONE + } + }) + animator.start() + } + + private fun animateArrow(from: Float, to: Float) { + val rotation = ObjectAnimator.ofFloat(mBinding.arrow, "rotation", from, to) + rotation.duration = animationDuration.toLong() + rotation.interpolator = AccelerateDecelerateInterpolator() + rotation.start() + } + + private fun getItemsHeight(): Int { + var height = 0 + for (i in 0 until mBinding.itemsContainer.childCount) { + val child = mBinding.itemsContainer.getChildAt(i) + child.measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + ) + height += child.measuredHeight + } + return height + } + + fun setOnItemSelectedListener(listener: OnItemSelectedListener) { + this.itemSelectedListener = listener + } + + interface OnItemSelectedListener { + fun onItemSelected(position: Int, item: SelectorItem) + } +} \ No newline at end of file diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/SelctorItem.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/SelctorItem.kt new file mode 100644 index 0000000..c6b8eee --- /dev/null +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/expandableSelector/SelctorItem.kt @@ -0,0 +1,10 @@ +package com.remax.visualnovel.ui.chat.ui.expandableSelector + +data class SelectorItem( + val name: String, + val description: String = "", + val pointsInfo: String = "", + val color: Int, + val isRecommended: Boolean = false, + var isSelected: Boolean = false +) \ No newline at end of file diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/StatusBarUtil2.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/StatusBarUtil2.kt new file mode 100644 index 0000000..a37bce6 --- /dev/null +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/StatusBarUtil2.kt @@ -0,0 +1,96 @@ +package com.remax.visualnovel.utils + +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.os.Build +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import androidx.annotation.ColorInt +import androidx.core.graphics.ColorUtils + + +object StatusBarUtil2 { + + // 初始化沉浸式状态栏 + fun initImmersive(activity: Activity, lightStatusBar: Boolean = false) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.window.apply { + clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + statusBarColor = Color.TRANSPARENT + decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + } + setLightStatusBar(activity, lightStatusBar) + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + } + } + + // 设置状态栏图标颜色 + fun setLightStatusBar(activity: Activity, light: Boolean) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val decorView = activity.window.decorView + var flags = decorView.systemUiVisibility + flags = if (light) { + flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } else { + flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + } + decorView.systemUiVisibility = flags + } + } + + // 获取状态栏高度 + fun getStatusBarHeight(context: Context): Int { + var result = 0 + val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android") + if (resourceId > 0) { + result = context.resources.getDimensionPixelSize(resourceId) + } + return result + } + + // 适配带状态栏高度的padding + fun View.addStatusBarPadding() { + setPadding( + paddingLeft, + paddingTop + getStatusBarHeight(context), + paddingRight, + paddingBottom + ) + } + + // 设置状态栏颜色(带透明度) + fun setStatusBarColor(activity: Activity, @ColorInt color: Int, alpha: Int = 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.window.statusBarColor = if (alpha > 0) { + ColorUtils.setAlphaComponent(color, alpha) + } else { + color + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + val statusBarView = View(activity).apply { + setBackgroundColor( + if (alpha > 0) { + ColorUtils.setAlphaComponent(color, alpha) + } else { + color + } + ) + layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + getStatusBarHeight(activity) + ).apply { + gravity = Gravity.TOP + } + } + (activity.window.decorView as ViewGroup).addView(statusBarView) + } + } +} \ No newline at end of file diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/BaseToolbar.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/CommonToolbar.kt similarity index 98% rename from VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/BaseToolbar.kt rename to VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/CommonToolbar.kt index 307de20..caa6357 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/BaseToolbar.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/widget/toolbar/CommonToolbar.kt @@ -8,14 +8,13 @@ import android.view.LayoutInflater import android.view.View import android.widget.ImageView import android.widget.LinearLayout -import android.widget.TextView import androidx.annotation.DrawableRes import com.remax.visualnovel.R import com.remax.visualnovel.widget.uitoken.view.UITokenImageView import com.remax.visualnovel.widget.uitoken.view.UITokenLinearLayout import com.remax.visualnovel.widget.uitoken.view.UITokenTextView -class BaseToolbar @JvmOverloads constructor( +class CommonToolbar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/VisualNovel/app/src/main/res/drawable/circle_selected.xml b/VisualNovel/app/src/main/res/drawable/circle_selected.xml new file mode 100644 index 0000000..01447a5 --- /dev/null +++ b/VisualNovel/app/src/main/res/drawable/circle_selected.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/drawable/circle_shape.xml b/VisualNovel/app/src/main/res/drawable/circle_shape.xml new file mode 100644 index 0000000..76bf22c --- /dev/null +++ b/VisualNovel/app/src/main/res/drawable/circle_shape.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml b/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml index 6cc7196..de6276a 100644 --- a/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml +++ b/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml @@ -1,49 +1,69 @@ - - - + + + + android:background="@mipmap/splash_bg" > - + + + + + + + + - + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/layout/activity_actor_chat2.xml b/VisualNovel/app/src/main/res/layout/activity_actor_chat2.xml deleted file mode 100644 index 01bbdc6..0000000 --- a/VisualNovel/app/src/main/res/layout/activity_actor_chat2.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/layout/layout_chat_menu_view.xml b/VisualNovel/app/src/main/res/layout/layout_chat_menu_view.xml index 3615eb3..2215a42 100644 --- a/VisualNovel/app/src/main/res/layout/layout_chat_menu_view.xml +++ b/VisualNovel/app/src/main/res/layout/layout_chat_menu_view.xml @@ -39,7 +39,7 @@ android:orientation="vertical" android:layout_marginTop="10dp" > diff --git a/VisualNovel/app/src/main/res/layout/layout_expand_select_view.xml b/VisualNovel/app/src/main/res/layout/layout_expand_select_view.xml new file mode 100644 index 0000000..b37ad7d --- /dev/null +++ b/VisualNovel/app/src/main/res/layout/layout_expand_select_view.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/layout/layout_expand_view_item.xml b/VisualNovel/app/src/main/res/layout/layout_expand_view_item.xml new file mode 100644 index 0000000..42db3ba --- /dev/null +++ b/VisualNovel/app/src/main/res/layout/layout_expand_view_item.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/values-v19/styles.xml b/VisualNovel/app/src/main/res/values-v19/styles.xml new file mode 100644 index 0000000..d4d88a9 --- /dev/null +++ b/VisualNovel/app/src/main/res/values-v19/styles.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/VisualNovel/app/src/main/res/values/attrs.xml b/VisualNovel/app/src/main/res/values/attrs.xml index 8437096..bf36681 100644 --- a/VisualNovel/app/src/main/res/values/attrs.xml +++ b/VisualNovel/app/src/main/res/values/attrs.xml @@ -1423,17 +1423,6 @@ - - @@ -1446,6 +1435,18 @@ + + + + + + + + + + + + diff --git a/VisualNovel/app/src/main/res/values/colors.xml b/VisualNovel/app/src/main/res/values/colors.xml index 9c1c1b2..48e9418 100644 --- a/VisualNovel/app/src/main/res/values/colors.xml +++ b/VisualNovel/app/src/main/res/values/colors.xml @@ -192,7 +192,8 @@ #ff666666 #fff6f6f6 - + + #fff6f6f6 diff --git a/VisualNovel/app/src/main/res/values/styles.xml b/VisualNovel/app/src/main/res/values/styles.xml index 52b2c87..2f0a592 100644 --- a/VisualNovel/app/src/main/res/values/styles.xml +++ b/VisualNovel/app/src/main/res/values/styles.xml @@ -6,6 +6,8 @@ @color/glo_color_grey_100 @color/glo_color_magenta_50 true + @color/transparent + true true @@ -241,10 +243,19 @@ - + + + + diff --git a/VisualNovel/app/src/main/res/values/ui_tokens.xml b/VisualNovel/app/src/main/res/values/ui_tokens.xml index c35ba6d..ea4ec4d 100644 --- a/VisualNovel/app/src/main/res/values/ui_tokens.xml +++ b/VisualNovel/app/src/main/res/values/ui_tokens.xml @@ -200,4 +200,9 @@ border.s border.m border.l + + + + + color.chat.setting.item.bg \ No newline at end of file