Procházet zdrojové kódy

feat: 个人水果机 (#10)

* feat: 个人水果机入口、背景音乐、全服横幅

* feat: 个人水果机私聊页挂件入口、房间外横幅

* refactor: 游戏可见性和游戏跳转统一到GameEntranceManager

* feat: 补充红点,url调整

* feat: 个人横幅uri调整

* feat: 个人横幅通知调整

* feat: 个人横幅通知调整

* fix: cocos游戏点击无效

* feat: 房间外玩个人水果机不可点击外部取消

* fix: 个人水果机链接

* fix: 游戏入口缓存区分用户

* fix: 任务中心倒计时入口挂件移动到首充挂件里

* fix: 弹窗调整点击外部参数可供外部调用

* fix: 红点显示 & 位置调整

* fix: 横幅svga资源问题

* fix: 阿语状态下,挂件没有镜像翻转

* fix: 横幅svga显示问题

* fix: banner点击节流

* fix: banner点击节流
linjiajia před 8 měsíci
rodič
revize
6b045b34be
100 změnil soubory, kde provedl 1692 přidání a 1233 odebrání
  1. 6 6
      app/src/main/java/com/adealink/weparty/commonui/dialogfragment/BaseDialogFragment.kt
  2. 5 1
      app/src/main/java/com/adealink/weparty/commonui/widget/CommonDialog.kt
  3. 5 1
      app/src/main/java/com/adealink/weparty/commonui/widget/banner/adapter/BannerAdapter.java
  4. 7 5
      app/src/main/java/com/adealink/weparty/commonui/widget/floatview/FloatViewFactory.kt
  5. 3 2
      app/src/main/java/com/adealink/weparty/commonui/widget/floatview/data/IFloatData.kt
  6. 283 0
      app/src/main/java/com/adealink/weparty/commonui/widget/floatview/view/BaseLongPressDragFloatView.kt
  7. 1 2
      app/src/main/java/com/adealink/weparty/module/couple/dialog/IntimateRelationShipCommonDialog.kt
  8. 20 3
      app/src/main/java/com/adealink/weparty/module/game/GameModule.kt
  9. 6 1
      app/src/main/java/com/adealink/weparty/module/game/IGameService.kt
  10. 1 0
      app/src/main/java/com/adealink/weparty/module/game/data/GameData.kt
  11. 148 0
      app/src/main/java/com/adealink/weparty/module/game/data/GameEntranceData.kt
  12. 141 0
      app/src/main/java/com/adealink/weparty/module/game/floatview/GameEntranceFloatView.kt
  13. 121 0
      app/src/main/java/com/adealink/weparty/module/game/floatview/GameEntranceFloatViewComp.kt
  14. 3 5
      app/src/main/java/com/adealink/weparty/module/game/viewmodel/IGameViewModel.kt
  15. 10 0
      app/src/main/java/com/adealink/weparty/module/headline/HeadlineModule.kt
  16. 4 0
      app/src/main/java/com/adealink/weparty/module/headline/IHeadlineService.kt
  17. 131 42
      app/src/main/java/com/adealink/weparty/module/operation/newuser/HomeBannerEntranceFloatView.kt
  18. 20 9
      app/src/main/java/com/adealink/weparty/module/operation/newuser/HomeBannerEntranceFloatViewComp.kt
  19. 0 2
      app/src/main/java/com/adealink/weparty/module/profile/PayToAddGIFDialog.kt
  20. 50 0
      app/src/main/java/com/adealink/weparty/module/profile/decorate/data/UserDecorateData.kt
  21. 14 13
      app/src/main/java/com/adealink/weparty/module/room/data/RoomNotifyData.kt
  22. 2 0
      app/src/main/java/com/adealink/weparty/module/room/datasource/local/RoomLocalService.kt
  23. 5 0
      app/src/main/java/com/adealink/weparty/module/task/Data.kt
  24. 1 1
      app/src/main/java/com/adealink/weparty/module/task/HomeIncomeFloatView.kt
  25. 0 174
      app/src/main/java/com/adealink/weparty/module/task/HomeTaskCountDownFloatView.kt
  26. 0 90
      app/src/main/java/com/adealink/weparty/module/task/HomeTaskCountDownViewComp.kt
  27. 4 4
      app/src/main/java/com/adealink/weparty/module/task/UserTaskManager.kt
  28. 9 1
      app/src/main/java/com/adealink/weparty/module/webview/WebViewDialogFragmentBuilder.kt
  29. 2 0
      app/src/main/java/com/adealink/weparty/ui/MainStartUpFragment.kt
  30. 11 4
      app/src/main/java/com/adealink/weparty/ui/home/BaseHomeFragment.kt
  31. 1 0
      app/src/main/java/com/adealink/weparty/url/H5Page.kt
  32. 5 0
      app/src/main/java/com/adealink/weparty/url/H5PageConfig.kt
  33. 5 0
      app/src/main/java/com/adealink/weparty/url/UrlConfig.kt
  34. binární
      app/src/main/res/drawable-xhdpi/common_greedy_personal_ic.webp
  35. 16 0
      app/src/main/res/layout/item_game_entrance_float_view.xml
  36. 0 2
      app/src/main/res/layout/item_home_banner_entrance_day_recharge_view.xml
  37. 2 4
      app/src/main/res/layout/item_home_banner_entrance_first_recharge_view.xml
  38. 0 2
      app/src/main/res/layout/item_home_banner_entrance_lottery_view.xml
  39. 5 16
      app/src/main/res/layout/item_home_banner_entrance_task_center_count_down_view.xml
  40. 31 0
      app/src/main/res/layout/layout_game_entrance_float_view.xml
  41. 5 4
      app/src/main/res/layout/layout_home_banner_entrance_view.xml
  42. 1 0
      app/src/main/res/values/strings.xml
  43. 1 1
      module/backpack/src/main/java/com/adealink/weparty/backpack/dialog/ReceiveCustomIdDialog.kt
  44. 1 2
      module/couple/src/main/java/com/adealink/weparty/couple/dialog/GuardUserDialog.kt
  45. 13 18
      module/game/src/main/java/com/adealink/weparty/game/GameServiceImpl.kt
  46. 17 0
      module/game/src/main/java/com/adealink/weparty/game/datasource/local/GameLocalService.kt
  47. 249 0
      module/game/src/main/java/com/adealink/weparty/game/manager/GameEntranceManager.kt
  48. 13 0
      module/game/src/main/java/com/adealink/weparty/game/manager/IGameEntranceManager.kt
  49. 1 1
      module/game/src/main/java/com/adealink/weparty/game/rocket/dialog/RocketUserRewardDialog.kt
  50. 8 34
      module/game/src/main/java/com/adealink/weparty/game/viewmodel/GameViewModel.kt
  51. 1 1
      module/gamehub/carrom/src/main/java/com/adealink/weparty/carrom/dialog/CarromGameResultDialog.kt
  52. 1 1
      module/gamehub/uno/src/main/java/com/adealink/weparty/uno/dialog/result/UnoGameResultDialog.kt
  53. 1 1
      module/gift/src/main/java/com/adealink/weparty/gift/luckygift/dialog/LuckGiftRewardDialog.kt
  54. 1 2
      module/gift/src/main/java/com/adealink/weparty/gift/treasure/view/GrabTreasureGiftResultDialog.kt
  55. binární
      module/headline/src/main/assets/headline_greedy_personal_global.svga
  56. 10 0
      module/headline/src/main/java/com/adealink/weparty/headline/HeadlineServiceImpl.kt
  57. 13 0
      module/headline/src/main/java/com/adealink/weparty/headline/floatview/GreedyPersonalGlobalHeadlineFloatData.kt
  58. 84 0
      module/headline/src/main/java/com/adealink/weparty/headline/floatview/GreedyPersonalGlobalHeadlineFloatView.kt
  59. 15 314
      module/headline/src/main/java/com/adealink/weparty/headline/fragment/HeadlineFragment.kt
  60. 38 0
      module/headline/src/main/java/com/adealink/weparty/headline/manager/HeadlineManager.kt
  61. 53 0
      module/headline/src/main/java/com/adealink/weparty/headline/view/GreedyPersonalGlobalHeadline.kt
  62. 3 0
      module/headline/src/main/java/com/adealink/weparty/headline/view/HeadlineViewBuilder.kt
  63. 5 40
      module/headline/src/main/java/com/adealink/weparty/headline/viewmodel/HeadlineViewModel.kt
  64. 2 2
      module/headline/src/main/res/layout/layout_lottery_common_global_headline.xml
  65. 1 0
      module/headline/src/main/res/values-ar/strings.xml
  66. 1 0
      module/headline/src/main/res/values-bn/strings.xml
  67. 1 0
      module/headline/src/main/res/values-es/strings.xml
  68. 1 0
      module/headline/src/main/res/values-hi/strings.xml
  69. 1 0
      module/headline/src/main/res/values-in/strings.xml
  70. 1 0
      module/headline/src/main/res/values-kk/strings.xml
  71. 1 0
      module/headline/src/main/res/values-ky/strings.xml
  72. 1 0
      module/headline/src/main/res/values-ms/strings.xml
  73. 1 0
      module/headline/src/main/res/values-pt/strings.xml
  74. 1 0
      module/headline/src/main/res/values-ru/strings.xml
  75. 1 0
      module/headline/src/main/res/values-ta/strings.xml
  76. 1 0
      module/headline/src/main/res/values-te/strings.xml
  77. 1 0
      module/headline/src/main/res/values-tg/strings.xml
  78. 1 0
      module/headline/src/main/res/values-th/strings.xml
  79. 1 0
      module/headline/src/main/res/values-tk/strings.xml
  80. 1 0
      module/headline/src/main/res/values-tl/strings.xml
  81. 1 0
      module/headline/src/main/res/values-tr/strings.xml
  82. 1 0
      module/headline/src/main/res/values-ur/strings.xml
  83. 1 0
      module/headline/src/main/res/values-uz/strings.xml
  84. 1 0
      module/headline/src/main/res/values-vi/strings.xml
  85. 1 0
      module/headline/src/main/res/values-zh-rTW/strings.xml
  86. 1 0
      module/headline/src/main/res/values-zh/strings.xml
  87. 1 0
      module/headline/src/main/res/values/strings.xml
  88. 2 1
      module/medal/src/main/java/com/adealink/weparty/medal/MedalPreviewDialog.kt
  89. 0 3
      module/micgrab/src/main/java/com/adealink/weparty/micgrab/help/MicGrabRuleDialog.kt
  90. 0 3
      module/micgrab/src/main/java/com/adealink/weparty/micgrab/result/MicGrabResultDialog.kt
  91. 1 2
      module/micgrab/src/main/java/com/adealink/weparty/micgrab/result/MicGrabResultFullScreenDialog.kt
  92. 1 1
      module/operation/src/main/java/com/adealink/weparty/operation/banner/BannerDialog.kt
  93. 1 1
      module/operation/src/main/java/com/adealink/weparty/operation/rateapp/RateAppDialog.kt
  94. 1 1
      module/pk/src/main/java/com/adealink/weparty/pk/dialog/RoomPKWinnerDialog.kt
  95. 2 2
      module/profile/src/main/java/com/adealink/weparty/profile/me/MeFragment.kt
  96. 14 296
      module/room/src/main/java/com/adealink/weparty/room/game/GameComp.kt
  97. 12 0
      module/room/src/main/java/com/adealink/weparty/room/game/RoomGameCenterPanelFragment.kt
  98. 20 18
      module/room/src/main/java/com/adealink/weparty/room/game/adapter/GameEntranceAdapter.kt
  99. 0 93
      module/room/src/main/java/com/adealink/weparty/room/game/data/GameEntranceData.kt
  100. 1 1
      module/room/src/main/java/com/adealink/weparty/room/gift/SendGiftFromChatDialog.kt

+ 6 - 6
app/src/main/java/com/adealink/weparty/commonui/dialogfragment/BaseDialogFragment.kt

@@ -53,7 +53,11 @@ open class BaseDialogFragment(@LayoutRes open val layoutId: Int) : DialogFragmen
     open val fgTag: String? = null
     private var loadingDialog: QMUITipDialog? = null
     open val cancelable: Boolean = true
-    open val canceledOnTouchOutside: Boolean = true
+    open var canceledOnTouchOutside: Boolean = true
+        set(value) {
+            field = value
+            dialog?.setCanceledOnTouchOutside(value)
+        }
     private var dismissCallback: (() -> Unit)? = null
     private var clickCallback: ((tag: Any?) -> Unit)? = null
 
@@ -95,10 +99,6 @@ open class BaseDialogFragment(@LayoutRes open val layoutId: Int) : DialogFragmen
 
     }
 
-    fun setCanceledOnTouchOutside(canceledOnTouchOutside: Boolean) {
-        dialog?.setCanceledOnTouchOutside(canceledOnTouchOutside)
-    }
-
     open fun show(transaction: FragmentTransaction): Int {
         return show(transaction, fgTag)
     }
@@ -222,7 +222,7 @@ open class BaseDialogFragment(@LayoutRes open val layoutId: Int) : DialogFragmen
         try {
             super.onStart()
             isCancelable = cancelable
-            setCanceledOnTouchOutside(canceledOnTouchOutside)
+            dialog?.setCanceledOnTouchOutside(canceledOnTouchOutside)
             val dialog = dialog ?: return
             val window = dialog.window ?: return
             resetWindowAttributes(window)

+ 5 - 1
app/src/main/java/com/adealink/weparty/commonui/widget/CommonDialog.kt

@@ -86,8 +86,12 @@ open class CommonDialog : BaseDialogFragment(R.layout.layout_common_dialog) {
 
     override val cancelable: Boolean
         get() = mCancelable
-    override val canceledOnTouchOutside: Boolean
+    override var canceledOnTouchOutside: Boolean
         get() = mCanceledOnTouchOutside
+        set(value) {
+            mCanceledOnTouchOutside = value
+            dialog?.setCanceledOnTouchOutside(value)
+        }
     private var positiveCountDownTimer: CountDownTimer? = null
     private var countDownTimerFormat: ((Long) -> String)? = null //倒计时格式化函数
     private var countDownFinishCallback: (() -> Unit)? = null //倒计时结束回调

+ 5 - 1
app/src/main/java/com/adealink/weparty/commonui/widget/banner/adapter/BannerAdapter.java

@@ -10,6 +10,7 @@ import com.adealink.weparty.commonui.widget.banner.config.BannerConfig;
 import com.adealink.weparty.commonui.widget.banner.holder.IViewHolder;
 import com.adealink.weparty.commonui.widget.banner.listener.OnBannerListener;
 import com.adealink.weparty.commonui.widget.banner.util.BannerUtils;
+import com.adealink.frame.util.ViewUtilKt;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -68,7 +69,10 @@ public abstract class BannerAdapter<T, VH extends RecyclerView.ViewHolder> exten
         holder.itemView.setTag(R.id.banner_pos_key, real);
         onBindView(holder, mDatas.get(real), real, getRealCount());
         if (mOnBannerListener != null) {
-            holder.itemView.setOnClickListener(view -> mOnBannerListener.OnBannerClick(data, real));
+            ViewUtilKt.onClick(holder.itemView, 500L, v -> {
+                mOnBannerListener.OnBannerClick(data, real);
+                return kotlin.Unit.INSTANCE;
+            });
         }
     }
 

+ 7 - 5
app/src/main/java/com/adealink/weparty/commonui/widget/floatview/FloatViewFactory.kt

@@ -10,16 +10,17 @@ import com.adealink.weparty.module.call.CallModule
 import com.adealink.weparty.module.couple.CoupleModule
 import com.adealink.weparty.module.follow.FollowModule
 import com.adealink.weparty.module.game.GameModule
+import com.adealink.weparty.module.game.floatview.GameEntranceFloatData
+import com.adealink.weparty.module.game.floatview.GameEntranceFloatView
+import com.adealink.weparty.module.headline.HeadlineModule
 import com.adealink.weparty.module.level.LevelModule
 import com.adealink.weparty.module.message.MessageModule
 import com.adealink.weparty.module.profile.ProfileModule
 import com.adealink.weparty.module.room.RoomModule
-import com.adealink.weparty.module.task.HomeBannerEntranceFloatData
-import com.adealink.weparty.module.task.HomeBannerEntranceFloatView
+import com.adealink.weparty.module.operation.newuser.HomeBannerEntranceFloatData
+import com.adealink.weparty.module.operation.newuser.HomeBannerEntranceFloatView
 import com.adealink.weparty.module.task.HomeIncomeFloatData
 import com.adealink.weparty.module.task.HomeIncomeFloatView
-import com.adealink.weparty.module.task.HomeTaskCountDownFloatData
-import com.adealink.weparty.module.task.HomeTaskCountDownFloatView
 import com.adealink.weparty.module.wallet.WalletModule
 import com.adealink.weparty.network.view.NetworkReconnectFloatData
 import com.adealink.weparty.network.view.NetworkReconnectFloatView
@@ -39,11 +40,12 @@ class FloatViewFactory : IFloatViewFactory {
             FloatWindowType.CALL_1V1_INCOMING -> CallModule.getIncomingFloatView(data)
             FloatWindowType.CALL_1V1_CALLING -> CallModule.getCallingFloatView(data)
             FloatWindowType.LEVEL_UPGRADE_HEADLINE -> LevelModule.getLevelUpgradeHeadlineFloatView(data)
-            FloatWindowType.HOME_TASK_COUNT_DOWN -> HomeTaskCountDownFloatView(data as HomeTaskCountDownFloatData)
             FloatWindowType.HOME_INCOME -> HomeIncomeFloatView(data as HomeIncomeFloatData)
             FloatWindowType.HOME_NEW_USER_LOTTERY -> HomeBannerEntranceFloatView(data as HomeBannerEntranceFloatData)
             FloatWindowType.MEMORY_USAGE -> SysMemoryUsageFloatView(data as SysMemoryUsageFloatData)
             FloatWindowType.ROCKET_HEADLINE -> GameModule.getRocketHeadlineFloatView(data)
+            FloatWindowType.GAME_ENTRANCE -> GameEntranceFloatView(data as GameEntranceFloatData)
+            FloatWindowType.GREEDY_PERSONAL_GLOBAL_HEADLINE -> HeadlineModule.getGreedyPersonalGlobalHeadlineFloatView(data)
         }
         return floatView as? V
     }

+ 3 - 2
app/src/main/java/com/adealink/weparty/commonui/widget/floatview/data/IFloatData.kt

@@ -12,11 +12,12 @@ enum class FloatWindowType(val type: String) {
     CALL_1V1_INCOMING("call_1v1_incoming"),
     CALL_1V1_CALLING("call_1v1_calling"),
     LEVEL_UPGRADE_HEADLINE("level_upgrade_headline"),
-    HOME_TASK_COUNT_DOWN("home_task_count_down"),
     HOME_INCOME("home_income"),
     HOME_NEW_USER_LOTTERY("home_new_user_lottery"),
     MEMORY_USAGE("memory_usage"),
-    ROCKET_HEADLINE("rocket_headline")
+    ROCKET_HEADLINE("rocket_headline"),
+    GAME_ENTRANCE("game_entrance"),
+    GREEDY_PERSONAL_GLOBAL_HEADLINE("greedy_personal_global_headline")
 }
 
 

+ 283 - 0
app/src/main/java/com/adealink/weparty/commonui/widget/floatview/view/BaseLongPressDragFloatView.kt

@@ -0,0 +1,283 @@
+package com.adealink.weparty.commonui.widget.floatview.view
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.os.Build
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.view.GestureDetector
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.view.animation.LinearInterpolator
+import com.adealink.frame.log.Log
+import com.adealink.frame.util.AppUtil
+import com.adealink.frame.util.DisplayUtil.getScreenHeight
+import com.adealink.frame.util.DisplayUtil.getScreenWidth
+import com.adealink.weparty.commonui.widget.floatview.data.IWindowFloatData
+import com.adealink.weparty.commonui.widget.floatview.data.TAG_FLOAT_DRAG_VIEW
+import com.adealink.weparty.commonui.widget.floatview.data.TAG_FLOAT_VIEW
+
+// 长按拖拽(适用于有可滑动子view的情况)
+abstract class BaseLongPressDragFloatView(baseFloatData: IWindowFloatData) : BaseWindowFloatView(baseFloatData) {
+
+    companion object {
+        private const val TAG = "BaseLongPressDragFloatView"
+        const val LOCATION_FIXED_NONE = 0
+        const val LOCATION_FIXED_LEFT = 1 shl 0
+        const val LOCATION_FIXED_RIGHT = 1 shl 1
+        const val LOCATION_FIXED_TOP = 1 shl 2
+        const val LOCATION_FIXED_BOTTOM = 1 shl 3
+    }
+
+    private val downPoint = Point()
+    private val lastPoint = Point()
+    private val movePoint = Point()
+    private val maxMovePoint = Point()
+    var maxX = getScreenWidth() - getLayoutParamWidth()
+    var maxY = getScreenHeight() - getLayoutParamHeight()
+
+    var toLeftAnim: ValueAnimator? = null
+    var toRightAnim: ValueAnimator? = null
+
+    private val gestureDetector: GestureDetector
+    private var isDragging = false
+
+
+    init {
+        gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
+            override fun onLongPress(e: MotionEvent) {
+                Log.d(TAG, "GestureDetector: onLongPress")
+                isDragging = true
+                performHapticFeedback()
+            }
+        })
+    }
+
+    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
+        gestureDetector.onTouchEvent(ev)
+        if (ev.action == MotionEvent.ACTION_DOWN) {
+            isDragging = false
+        }
+        if (isDragging) {
+            return onTouchEvent(ev)
+        }
+        return super.dispatchTouchEvent(ev)
+    }
+
+    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+        return isDragging
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                downPoint.y = event.rawY.toInt()
+                lastPoint.x = downPoint.x
+                lastPoint.y = downPoint.y
+            }
+
+            MotionEvent.ACTION_MOVE -> {
+                movePoint.x = event.rawX.toInt()
+                movePoint.y = event.rawY.toInt()
+                updateViewLayout(movePoint.x - lastPoint.x, movePoint.y - lastPoint.y)
+                maxMovePoint.x = Math.max(lastPoint.x, movePoint.x)
+                maxMovePoint.y = Math.max(lastPoint.y, movePoint.y)
+                lastPoint.x = movePoint.x
+                lastPoint.y = movePoint.y
+            }
+
+            MotionEvent.ACTION_UP -> {
+                if (isDragging) {
+                    if (applySnapToEdge()) {
+                        moveToLocation()
+                    }
+                }
+                isDragging = false
+            }
+
+            else -> {
+
+            }
+        }
+        return true
+    }
+
+    private fun performHapticFeedback() {
+        try {
+            val vibrator = AppUtil.getSystemService<Vibrator>(Context.VIBRATOR_SERVICE)
+            if (vibrator?.hasVibrator() == true) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                    vibrator.vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE))
+                } else {
+                    vibrator.vibrate(50)
+                }
+            }
+        } catch (e: Exception) {
+            Log.e(TAG, "stay more than 2 seconds, vibrate fail, for ${e.message}", e)
+        }
+
+    }
+
+    private fun moveToLocation() {
+
+        val fixedLocation = getFixedLocation()
+        //horizontal
+        if ((fixedLocation and LOCATION_FIXED_LEFT) != 0) {
+            moveToLeftWithAnim()
+        } else if ((fixedLocation and LOCATION_FIXED_RIGHT) != 0) {
+            moveToRightWithAnim()
+        }
+        //vertical
+        if ((fixedLocation and LOCATION_FIXED_TOP) != 0) {
+            moveToTop()
+        } else if ((fixedLocation and LOCATION_FIXED_BOTTOM) != 0) {
+            moveToBottom()
+        }
+
+    }
+
+    private fun updateViewLayout(changeX: Int, changeY: Int) {
+        val newX = changeX + windowParams.x
+        val newY = changeY + windowParams.y
+        if (newX in 0 until maxX) {
+            windowParams.x = newX
+        }
+        if (newY in 0 until maxY) {
+            windowParams.y = newY
+        }
+        updateViewLayout()
+    }
+
+
+    private fun moveToRightWithAnim() {
+        val location = IntArray(2)
+        getLocationOnScreen(location)
+        val dx = location[0]
+        toRightAnim = ValueAnimator.ofInt(dx, maxX).apply {
+            addUpdateListener {
+                val data = it.animatedValue as Int
+                windowParams.x = data
+                updateViewLayout()
+            }
+            interpolator = LinearInterpolator()
+            duration = 100
+        }
+        toRightAnim?.start()
+    }
+
+
+    private fun moveToLeftWithAnim() {
+        val location = IntArray(2)
+        getLocationOnScreen(location)
+        val dx = location[0]
+        toLeftAnim = ValueAnimator.ofInt(dx, 0).apply {
+            addUpdateListener {
+                val data = it.animatedValue as Int
+                windowParams.x = data
+                updateViewLayout()
+            }
+            interpolator = LinearInterpolator()
+            duration = 100
+        }
+        toLeftAnim?.start()
+    }
+
+    private fun moveToTop() {
+        var dy = lastPoint.y
+        while (dy > 0) {
+            updateViewLayout(0, -1)
+            dy--
+        }
+    }
+
+    private fun moveToBottom() {
+        var dy = getScreenHeight() - lastPoint.y
+        while (dy > 0) {
+            updateViewLayout(0, 1)
+            dy--
+        }
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        setMeasuredDimension(
+            getDefaultSize(0, widthMeasureSpec),
+            getDefaultSize(0, heightMeasureSpec)
+        )
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+    }
+
+    override val windowParams = WindowManager.LayoutParams().apply {
+        width = getLayoutParamWidth()
+        height = getLayoutParamHeight()
+        format = PixelFormat.TRANSLUCENT
+        flags = (WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
+        gravity = Gravity.START or Gravity.TOP
+        val layoutX = getLayoutParamX()
+        val layoutY = getLayoutParamY()
+        if (layoutX != null && layoutY != null) {
+            x = layoutX
+            y = layoutY
+        } else {
+            x =
+                if (getFixedLocation() == LOCATION_FIXED_LEFT) 0 else getScreenWidth() - width
+            y =
+                if (getFixedLocation() == LOCATION_FIXED_TOP) 0 else getScreenHeight() - height
+        }
+    }
+
+    private fun updateViewLayout() {
+        if (windowParams.token != null) {
+            try {
+                windowManager?.getCurrentWindowManager()?.updateViewLayout(this@BaseLongPressDragFloatView, windowParams)
+            } catch (e: Throwable) {
+                Log.e(
+                    TAG_FLOAT_VIEW,
+                    "$TAG_FLOAT_DRAG_VIEW, updateViewLayout crash, $e"
+                )
+            }
+        }
+    }
+
+    abstract fun getLayoutParamWidth(): Int
+    abstract fun getLayoutParamHeight(): Int
+    abstract fun getLayoutParamX(): Int?
+    abstract fun getLayoutParamY(): Int?
+
+    /**
+     * 悬浮view,控制是否吸边效果
+     */
+    abstract fun applySnapToEdge(): Boolean
+
+    protected open fun getFixedLocation(): Int {
+        val location = IntArray(2)
+        getLocationOnScreen(location)
+        return if (context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+            if (location[0] + getLayoutParamWidth() / 2 <= getScreenWidth() / 2) {
+                LOCATION_FIXED_LEFT
+            } else {
+                LOCATION_FIXED_RIGHT
+            }
+        } else {
+            if (location[0] + getLayoutParamWidth() / 2 <= getScreenWidth() / 2) {
+                LOCATION_FIXED_LEFT
+            } else {
+                LOCATION_FIXED_RIGHT
+            }
+        }
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        toLeftAnim?.cancel()
+        toLeftAnim = null
+        toRightAnim?.cancel()
+        toRightAnim = null
+    }
+}

+ 1 - 2
app/src/main/java/com/adealink/weparty/module/couple/dialog/IntimateRelationShipCommonDialog.kt

@@ -54,8 +54,7 @@ class IntimateRelationShipCommonDialog :
 
     override val cancelable: Boolean
         get() = mCancelable
-    override val canceledOnTouchOutside: Boolean
-        get() = mCanceledOnTouchOutside
+    override var canceledOnTouchOutside: Boolean = mCanceledOnTouchOutside
 
     override fun onStart() {
         super.onStart()

+ 20 - 3
app/src/main/java/com/adealink/weparty/module/game/GameModule.kt

@@ -8,6 +8,7 @@ import com.adealink.weparty.cocosgame.data.Game
 import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
 import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
 import com.adealink.weparty.module.game.data.CommonActivityRewardInfoReq
+import com.adealink.weparty.module.game.data.GameEntranceType
 import com.adealink.weparty.module.game.data.GameShowConfig
 import com.adealink.weparty.module.game.data.GameType
 import com.adealink.weparty.module.game.data.ReceiveRewardReq
@@ -17,6 +18,7 @@ import com.adealink.weparty.module.game.viewmodel.IGameViewModel
 import com.adealink.weparty.module.game.viewmodel.IMicCharmPKViewModel
 import com.adealink.weparty.module.game.viewmodel.IRedPacketViewModel
 import com.adealink.weparty.module.game.viewmodel.IRouletteViewModel
+import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.data.RedPacketInfo
 
 /**
@@ -58,10 +60,18 @@ object GameModule : BaseDynamicModule<IGameService>(IGameService::class), IGameS
         return getService().isShowRoulette(roomId)
     }
 
-    override suspend fun isGameShow(configTypes: List<Int>): Map<Int, GameShowConfig> {
+    override suspend fun isGameShow(configTypes: List<DecorType>): Map<DecorType, GameShowConfig> {
         return getService().isGameShow(configTypes)
     }
 
+    override suspend fun getAllGameShowConfigs(): Map<DecorType, GameShowConfig> {
+        return getService().getAllGameShowConfigs()
+    }
+
+    override fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean) {
+        return getService().navigateToGame(gameType, canceledOnTouchOutside)
+    }
+
     override suspend fun getActivityGameRewardInfo(req: CommonActivityRewardInfoReq): com.adealink.weparty.module.game.data.GameActivityRewardInfo? {
         return getService().getActivityGameRewardInfo(req)
     }
@@ -135,8 +145,15 @@ object GameModule : BaseDynamicModule<IGameService>(IGameService::class), IGameS
                 return false
             }
 
-            override suspend fun isGameShow(configTypes: List<Int>): Map<Int, GameShowConfig> {
-                return hashMapOf()
+            override suspend fun isGameShow(configTypes: List<DecorType>): Map<DecorType, GameShowConfig> {
+                return emptyMap()
+            }
+
+            override suspend fun getAllGameShowConfigs(): Map<DecorType, GameShowConfig> {
+                return emptyMap()
+            }
+
+            override fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean) {
             }
 
             override suspend fun getActivityGameRewardInfo(req: CommonActivityRewardInfoReq): com.adealink.weparty.module.game.data.GameActivityRewardInfo? {

+ 6 - 1
app/src/main/java/com/adealink/weparty/module/game/IGameService.kt

@@ -8,6 +8,7 @@ import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
 import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
 import com.adealink.weparty.module.game.data.CommonActivityRewardInfoReq
 import com.adealink.weparty.module.game.data.GameActivityRewardInfo
+import com.adealink.weparty.module.game.data.GameEntranceType
 import com.adealink.weparty.module.game.data.GameShowConfig
 import com.adealink.weparty.module.game.data.GameType
 import com.adealink.weparty.module.game.data.ReceiveRewardReq
@@ -17,6 +18,7 @@ import com.adealink.weparty.module.game.viewmodel.IGameViewModel
 import com.adealink.weparty.module.game.viewmodel.IMicCharmPKViewModel
 import com.adealink.weparty.module.game.viewmodel.IRedPacketViewModel
 import com.adealink.weparty.module.game.viewmodel.IRouletteViewModel
+import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.data.RedPacketInfo
 
 /**
@@ -31,7 +33,6 @@ interface IGameService : IService<IGameService> {
     fun getRocketViewModel(owner: ViewModelStoreOwner): IRocketViewModel?
     fun updateCurRedPacketInfo(redPacketInfo: RedPacketInfo?)
     suspend fun isShowRoulette(roomId: Long): Boolean
-    suspend fun isGameShow(configTypes: List<Int>): Map<Int, GameShowConfig>
     suspend fun getActivityGameRewardInfo(req: CommonActivityRewardInfoReq) : GameActivityRewardInfo?
     suspend fun getUserGameLevelInfo(uids: List<Long>) : UserGameLevelInfoResult?
     suspend fun toReceiveGameReward(req: ReceiveRewardReq) : Rlt<Boolean>?
@@ -48,4 +49,8 @@ interface IGameService : IService<IGameService> {
 
     fun initRocket()
     fun getRocketHeadlineFloatView(data: IFloatData): BaseFloatView<out IFloatData>?
+
+    suspend fun isGameShow(configTypes: List<DecorType>): Map<DecorType, GameShowConfig>
+    suspend fun getAllGameShowConfigs(): Map<DecorType, GameShowConfig>
+    fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean = true)
 }

+ 1 - 0
app/src/main/java/com/adealink/weparty/module/game/data/GameData.kt

@@ -43,6 +43,7 @@ data class GameShowConfig(
     @SerializedName("showInRoomActPps") val showInRoomActPps: Boolean, //房间右下角游戏组件开关
     @GsonNullable
     @SerializedName("url") val url: String? = null, //Slot游戏
+    @SerializedName("showOutRoomGame") val showOutRoomGame: Boolean = false,
 )
 
 data class CommonActivityRewardInfoReq(

+ 148 - 0
app/src/main/java/com/adealink/weparty/module/game/data/GameEntranceData.kt

@@ -0,0 +1,148 @@
+package com.adealink.weparty.module.game.data
+
+import android.os.Bundle
+import androidx.fragment.app.FragmentActivity
+import com.adealink.frame.locale.language.languageManager
+import com.adealink.frame.router.Router
+import com.adealink.frame.util.AppUtil
+import com.adealink.weparty.commonui.dialogfragment.BaseDialogFragment
+import com.adealink.weparty.module.game.Game
+import com.adealink.weparty.module.game.GameModule
+import com.adealink.weparty.module.operation.Operation
+import com.adealink.weparty.module.operation.Operation.RechargePackage.Companion.EXTRA_SOURCE
+import com.adealink.weparty.module.operation.Operation.RechargePackage.Companion.SOURCE_ROOM_OPERATION
+import com.adealink.weparty.module.operation.rechargepackage.data.RechargePackageConfig
+import com.opensource.svgaplayer.utils.UriUtil
+
+/**
+ * Created by sunxiaodong on 2021/8/2.
+ */
+
+enum class GameEntranceType(val type: Int) {
+    LUCKY_FRUIT(0),
+    RECHARGE_PACKAGE(1),
+    JACKPOT(2),
+    DAILY_RECHARGE(3),
+    GREEDY_PRO(4),
+    LUCKY_PRO(6),
+    GREEDY_BOX(7),
+    JACKPOT_SLOT(8),
+    TEEN_PATTI(10),
+    RUSSIAN_ROULETTE(11),
+    TEXAS_COWBOY(12),
+    DRAGON_TIGER_FIGHT(13),
+    ROCKET(14),
+    GREEDY_PERSONAL(15)
+}
+
+sealed class GameEntrance(val icon: String, val type: GameEntranceType, val onClick: (() -> Unit) = { })
+
+
+class RechargePackageEntrance(val config: RechargePackageConfig) : GameEntrance(
+    config.getIcon(languageManager?.getLanguageCode()),
+    GameEntranceType.RECHARGE_PACKAGE,
+    {
+        val topActivity = AppUtil.currentActivity
+        if (topActivity is FragmentActivity) {
+            Router.getRouterInstance<BaseDialogFragment>(Operation.RechargePackage.PATH)
+                ?.apply {
+                    arguments = Bundle().apply {
+                        putInt(EXTRA_SOURCE, SOURCE_ROOM_OPERATION)
+                    }
+                }
+                ?.show(topActivity.supportFragmentManager)
+        }
+    }
+)
+
+class DailyRechargeEntrance : GameEntrance(
+    "",
+    GameEntranceType.DAILY_RECHARGE,
+    {
+        val fragment =
+            Router.getRouterInstance<BaseDialogFragment>(Operation.RechargeDaily.PATH)
+        val topActivity = AppUtil.currentActivity
+        if (topActivity is FragmentActivity) {
+            fragment?.show(topActivity.supportFragmentManager)
+        }
+    }
+)
+
+data class RocketEntrance(var rocketLevel: Int, var progress: Int) : GameEntrance(
+    "",
+    GameEntranceType.ROCKET,
+    {
+        val topActivity = AppUtil.currentActivity
+        if (topActivity is FragmentActivity) {
+            Router.getRouterInstance<BaseDialogFragment>(Game.Rocket.RocketPanel.PATH)
+                ?.show(topActivity.supportFragmentManager)
+        }
+
+    }
+)
+
+class LuckyFruitEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_lucky_fruit_ic).toString(),
+    GameEntranceType.LUCKY_FRUIT,
+    { GameModule.navigateToGame(GameEntranceType.LUCKY_FRUIT) }
+)
+
+class SlotEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_jackpot_ic).toString(),
+    GameEntranceType.JACKPOT,
+    { GameModule.navigateToGame(GameEntranceType.JACKPOT) }
+)
+
+class GreedyProEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_greedy_pro_ic).toString(),
+    GameEntranceType.GREEDY_PRO,
+    { GameModule.navigateToGame(GameEntranceType.GREEDY_PRO) }
+)
+
+class GreedyBoxEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_greedy_box_ic).toString(),
+    GameEntranceType.GREEDY_BOX,
+    { GameModule.navigateToGame(GameEntranceType.GREEDY_BOX) }
+)
+
+class SlotProEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_jackpot_slot_ic).toString(),
+    GameEntranceType.JACKPOT_SLOT,
+    { GameModule.navigateToGame(GameEntranceType.JACKPOT_SLOT) }
+)
+
+class LuckyProEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_lucky_pro_ic).toString(),
+    GameEntranceType.LUCKY_PRO,
+    { GameModule.navigateToGame(GameEntranceType.LUCKY_PRO) }
+)
+
+class TeenPattiEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_teen_patti_ic).toString(),
+    GameEntranceType.TEEN_PATTI,
+    { GameModule.navigateToGame(GameEntranceType.TEEN_PATTI) }
+)
+
+class RussianRouletteEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_russian_roulette_ic).toString(),
+    GameEntranceType.RUSSIAN_ROULETTE,
+    { GameModule.navigateToGame(GameEntranceType.RUSSIAN_ROULETTE) }
+)
+
+class TexasCowboyEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_texas_cowboy_ic).toString(),
+    GameEntranceType.TEXAS_COWBOY,
+    { GameModule.navigateToGame(GameEntranceType.TEXAS_COWBOY) }
+)
+
+class DragonTigerEntrance : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_dragon_tiger_ic).toString(),
+    GameEntranceType.DRAGON_TIGER_FIGHT,
+    { GameModule.navigateToGame(GameEntranceType.DRAGON_TIGER_FIGHT) }
+)
+
+class GreedyPersonalEntrance(canceledOnTouchOutside: Boolean = true) : GameEntrance(
+    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_greedy_personal_ic).toString(),
+    GameEntranceType.GREEDY_PERSONAL,
+    { GameModule.navigateToGame(GameEntranceType.GREEDY_PERSONAL, canceledOnTouchOutside) }
+)

+ 141 - 0
app/src/main/java/com/adealink/weparty/module/game/floatview/GameEntranceFloatView.kt

@@ -0,0 +1,141 @@
+package com.adealink.weparty.module.game.floatview
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.FragmentActivity
+import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.router.Router
+import com.adealink.frame.util.DisplayUtil
+import com.adealink.frame.util.onClick
+import com.adealink.weparty.AppModule
+import com.adealink.weparty.commonui.ext.dp
+import com.adealink.weparty.commonui.ext.show
+import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
+import com.adealink.weparty.commonui.widget.banner.adapter.BannerAdapter
+import com.adealink.weparty.commonui.widget.floatview.data.FloatWindowType
+import com.adealink.weparty.commonui.widget.floatview.data.IWindowFloatData
+import com.adealink.weparty.commonui.widget.floatview.data.MODE_APPLICATION
+import com.adealink.weparty.commonui.widget.floatview.view.BaseLongPressDragFloatView
+import com.adealink.weparty.databinding.ItemGameEntranceFloatViewBinding
+import com.adealink.weparty.databinding.LayoutGameEntranceFloatViewBinding
+import com.adealink.weparty.module.game.data.GameEntrance
+import com.adealink.weparty.module.message.Message
+import com.adealink.weparty.ui.home.util.HomeUIUtil
+
+class GameEntranceFloatData : IWindowFloatData {
+    override fun windowType(): FloatWindowType = FloatWindowType.GAME_ENTRANCE
+
+    override fun windowMode() = MODE_APPLICATION
+}
+
+@SuppressLint("ViewConstructor")
+class GameEntranceFloatView(floatData: GameEntranceFloatData) : BaseLongPressDragFloatView(floatData) {
+
+    private var binding: LayoutGameEntranceFloatViewBinding? = null
+
+    private val isShow: Boolean
+        get() {
+            //只在message tab展示或者私聊页展示
+            val activity = windowManager?.currentActivity?.get() ?: return false
+            if (activity.javaClass.name == Router.getClazz(AppModule.Main.PATH)?.name && HomeUIUtil.isInMessageTab()) {
+                return true
+            }
+            return hashSetOf(
+                Router.getClazz(Message.Conversation.PATH)?.name ?: "",
+            ).contains(activity.javaClass.name)
+        }
+
+    override fun onCreate() {
+        super.onCreate()
+        val binding = LayoutGameEntranceFloatViewBinding.inflate(LayoutInflater.from(context))
+        this.binding = binding
+        setContentView(binding.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
+        show(isShow)
+    }
+
+    fun setEntranceList(
+        list: List<GameEntrance>,
+        handleBannerClick: (clickEntrance: GameEntrance) -> Unit,
+        closeClick: () -> Unit
+    ) {
+        val binding = binding ?: return
+        val bannerAdapter = GameEntranceFloatViewAdapter(list)
+        binding.bannerView.apply {
+            setLoopTime(6 * 1000)
+            addBannerLifecycleObserver(this@GameEntranceFloatView)
+            setAdapter(bannerAdapter)
+            setOnBannerListener { data, _ ->
+                val gameEntrance = data as? GameEntrance ?: return@setOnBannerListener
+                handleBannerClick(gameEntrance)
+            }
+        }
+
+        binding.btnClose.onClick {
+            closeClick()
+        }
+    }
+
+
+    override fun onActivityChange(activity: Activity) {
+        super.onActivityChange(activity)
+        show(isShow)
+    }
+
+    fun onHomeTabChange() {
+        show(isShow)
+    }
+
+    override fun getLayoutParamWidth(): Int {
+        return 71.dp()
+    }
+
+    override fun getLayoutParamHeight(): Int {
+        return 73.dp()
+    }
+
+    override fun getLayoutParamX(): Int {
+        return if (DisplayUtil.isRtlLayout()) {
+            0
+        } else {
+            DisplayUtil.getScreenWidth() - getLayoutParamWidth()
+        }
+    }
+
+    override fun getLayoutParamY(): Int {
+        val homeTabHeight = 54.dp()
+        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 80.dp() - homeTabHeight
+    }
+
+    override fun applySnapToEdge(): Boolean {
+        return true
+    }
+
+    inner class GameEntranceFloatViewAdapter(entrances: List<GameEntrance>) :
+        BannerAdapter<GameEntrance, GameEntranceFloatViewItemViewHolder>(entrances) {
+
+        override fun onCreateHolder(
+            parent: ViewGroup,
+            viewType: Int,
+        ): GameEntranceFloatViewItemViewHolder {
+            val inflater = LayoutInflater.from(parent.context)
+            return GameEntranceFloatViewItemViewHolder(ItemGameEntranceFloatViewBinding.inflate(inflater, parent, false))
+        }
+
+        override fun onBindView(holder: GameEntranceFloatViewItemViewHolder, data: GameEntrance, position: Int, size: Int) {
+            holder.update(data)
+        }
+
+    }
+
+    inner class GameEntranceFloatViewItemViewHolder(binding: ItemGameEntranceFloatViewBinding) :
+        BindingViewHolder<ItemGameEntranceFloatViewBinding>(binding) {
+
+        fun update(data: GameEntrance) {
+            binding.icon.setImageUrl(data.icon)
+        }
+    }
+}

+ 121 - 0
app/src/main/java/com/adealink/weparty/module/game/floatview/GameEntranceFloatViewComp.kt

@@ -0,0 +1,121 @@
+package com.adealink.weparty.module.game.floatview
+
+import android.content.Intent
+import androidx.lifecycle.LifecycleOwner
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.log.Log
+import com.adealink.frame.mvvm.view.ViewComponent
+import com.adealink.frame.util.runOnUiThread
+import com.adealink.weparty.commonui.widget.floatview.FloatViewFactory
+import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
+import com.adealink.weparty.module.game.GameModule
+import com.adealink.weparty.module.game.data.GameEntrance
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.profile.decorate.data.toGameEntrance
+import com.adealink.weparty.module.profile.decorate.data.toGameEntranceType
+
+class GameEntranceFloatViewComp(lifecycleOwner: LifecycleOwner) : ViewComponent(lifecycleOwner) {
+
+    companion object {
+        private const val TAG = "GameEntranceFloatViewComp"
+
+        //用户主动关闭,没必要再次添加到floatView
+        var userClose = false
+    }
+
+    private val floatViewFactory by fastLazy { FloatViewFactory() }
+    private val gameViewModel by fastLazy {
+        GameModule.getGameViewModel(viewModelStoreOwner)
+    }
+    private val gameEntrances = arrayListOf<GameEntrance>()
+    private val gameEntranceMap = hashMapOf<GameEntranceType, GameEntrance>()
+    private var floatView: GameEntranceFloatView? = null
+
+    override fun onCreate() {
+        super.onCreate()
+        loadData()
+    }
+
+    private fun loadData() {
+        gameViewModel?.getAllGameShowConfigs()?.observe(viewLifecycleOwner) { configMap ->
+            for ((decorType, gameShowConfig) in configMap) {
+                if (gameShowConfig.showOutRoomGame) {
+                    val entrance = decorType.toGameEntrance(false) ?: continue
+                    addEntrance(entrance)
+                } else {
+                    val entranceType = decorType.toGameEntranceType() ?: continue
+                    removeEntrance(entranceType)
+                }
+            }
+            updateEntranceList()
+        }
+    }
+
+    private fun addEntrance(entrance: GameEntrance) {
+        val existEntrance = gameEntranceMap[entrance.type]
+        if (existEntrance != null) {
+            return
+        }
+        gameEntranceMap[entrance.type] = entrance
+        gameEntrances.add(entrance)
+    }
+
+    private fun removeEntrance(entranceType: GameEntranceType) {
+        gameEntranceMap.remove(entranceType)?.let {
+            gameEntrances.remove(it)
+        }
+    }
+
+    private fun updateEntranceList() {
+        if (userClose) {
+            return
+        }
+        if (gameEntrances.isNotEmpty()) {
+            addFloatView()
+            floatView?.setEntranceList(
+                gameEntrances,
+                { it.onClick() },
+                {
+                    removeFloatView("User close")
+                    userClose = true
+                }
+            )
+        } else {
+            removeFloatView("No entrances")
+        }
+    }
+
+    private fun addFloatView() {
+        Log.d(TAG, "addFloatView")
+        runOnUiThread {
+            if (floatView != null) {
+                return@runOnUiThread
+            }
+            floatView = floatViewFactory.createFloatView<GameEntranceFloatView>(GameEntranceFloatData())?.also { view ->
+                WindowManagerProxy.getWindowManager().addView(view)
+            }
+        }
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        removeFloatView("GameEntranceFloatViewComp onDestroy")
+    }
+
+    private fun removeFloatView(reason: String) {
+        Log.d(TAG, "removeFloatView")
+        floatView?.let {
+            WindowManagerProxy.getWindowManager().removeView(it, reason = reason)
+        }
+        floatView = null
+    }
+
+    override fun onNewIntent(intent: Intent?) {
+        super.onNewIntent(intent)
+        loadData()
+    }
+
+    fun onHomeTabChange() {
+        floatView?.onHomeTabChange()
+    }
+}

+ 3 - 5
app/src/main/java/com/adealink/weparty/module/game/viewmodel/IGameViewModel.kt

@@ -3,12 +3,11 @@ package com.adealink.weparty.module.game.viewmodel
 import androidx.lifecycle.LiveData
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.network.data.Res
-import com.adealink.weparty.config.GameVersionConfig
-import com.adealink.weparty.config.GlobalConfigType
 import com.adealink.weparty.module.game.data.GameShowConfig
 import com.adealink.weparty.module.game.data.GameType
 import com.adealink.weparty.module.game.data.LuckyFruitShowRes
 import com.adealink.weparty.module.game.data.SlotConfigInfoRes
+import com.adealink.weparty.module.profile.decorate.data.DecorType
 
 /**
  * Created by sunxiaodong on 2021/7/1.
@@ -24,7 +23,6 @@ interface IGameViewModel {
 
     fun isShowSlot(): LiveData<Rlt<Res<SlotConfigInfoRes>>>
 
-    fun isGameShow(configTypes: List<Int>): LiveData<Map<Int, GameShowConfig>>
-
-    fun checkGameValid(type: GlobalConfigType): LiveData<Pair<Boolean, GameVersionConfig?>>
+    fun isGameShow(configTypes: List<DecorType>): LiveData<Map<DecorType, GameShowConfig>>
+    fun getAllGameShowConfigs(): LiveData<Map<DecorType, GameShowConfig>>
 }

+ 10 - 0
app/src/main/java/com/adealink/weparty/module/headline/HeadlineModule.kt

@@ -3,6 +3,8 @@ package com.adealink.weparty.module.headline
 import androidx.lifecycle.ViewModelStoreOwner
 import com.adealink.frame.aab.BaseDynamicModule
 import com.adealink.weparty.R
+import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
+import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
 import com.adealink.weparty.module.headline.listener.IHeadlineListener
 import com.adealink.weparty.module.headline.viewmodel.IHeadlineViewModel
 
@@ -19,6 +21,10 @@ object HeadlineModule: BaseDynamicModule<IHeadlineService>(IHeadlineService::cla
                 return null
             }
 
+            override fun getGreedyPersonalGlobalHeadlineFloatView(data: IFloatData): BaseFloatView<out IFloatData>? {
+                return null
+            }
+
             override fun addListener(l: IHeadlineListener) {
             }
 
@@ -43,6 +49,10 @@ object HeadlineModule: BaseDynamicModule<IHeadlineService>(IHeadlineService::cla
         return getService().getHeadLineViewModel(owner)
     }
 
+    override fun getGreedyPersonalGlobalHeadlineFloatView(data: IFloatData): BaseFloatView<out IFloatData>? {
+        return getService().getGreedyPersonalGlobalHeadlineFloatView(data)
+    }
+
     override fun addListener(l: IHeadlineListener) {
         return getService().addListener(l)
     }

+ 4 - 0
app/src/main/java/com/adealink/weparty/module/headline/IHeadlineService.kt

@@ -2,6 +2,8 @@ package com.adealink.weparty.module.headline
 
 import androidx.lifecycle.ViewModelStoreOwner
 import com.adealink.frame.aab.IService
+import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
+import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
 import com.adealink.weparty.module.headline.listener.IHeadlineListener
 import com.adealink.weparty.module.headline.viewmodel.IHeadlineViewModel
 
@@ -11,6 +13,8 @@ interface IHeadlineService: IService<IHeadlineService> {
 
     fun getHeadLineViewModel(owner: ViewModelStoreOwner): IHeadlineViewModel?
 
+    fun getGreedyPersonalGlobalHeadlineFloatView(data: IFloatData): BaseFloatView<out IFloatData>?
+
     fun addListener(l: IHeadlineListener)
 
     fun removeListener(l: IHeadlineListener)

+ 131 - 42
app/src/main/java/com/adealink/weparty/module/operation/newuser/HomeBannerEntranceFloatView.kt

@@ -1,7 +1,8 @@
-package com.adealink.weparty.module.task
+package com.adealink.weparty.module.operation.newuser
 
 import android.app.Activity
 import android.os.Bundle
+import android.os.CountDownTimer
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -9,9 +10,11 @@ import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.setViewTreeLifecycleOwner
 import androidx.lifecycle.setViewTreeViewModelStoreOwner
 import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.dot.NumDot
 import com.adealink.frame.router.Router
 import com.adealink.frame.util.AppUtil
 import com.adealink.frame.util.DisplayUtil
+import com.adealink.frame.util.ONE_SECOND
 import com.adealink.frame.util.onClick
 import com.adealink.weparty.AppModule
 import com.adealink.weparty.commonui.dialogfragment.BaseDialogFragment
@@ -24,13 +27,16 @@ import com.adealink.weparty.commonui.widget.floatview.data.FloatWindowType
 import com.adealink.weparty.commonui.widget.floatview.data.IWindowFloatData
 import com.adealink.weparty.commonui.widget.floatview.data.MODE_APPLICATION
 import com.adealink.weparty.commonui.widget.floatview.view.BaseDragFloatView
+import com.adealink.weparty.commonui.widget.floatview.view.BaseLongPressDragFloatView
 import com.adealink.weparty.databinding.ItemHomeBannerEntranceDayRechargeViewBinding
 import com.adealink.weparty.databinding.ItemHomeBannerEntranceFirstRechargeViewBinding
 import com.adealink.weparty.databinding.ItemHomeBannerEntranceLotteryViewBinding
+import com.adealink.weparty.databinding.ItemHomeBannerEntranceTaskCenterCountDownViewBinding
 import com.adealink.weparty.databinding.LayoutHomeBannerEntranceViewBinding
 import com.adealink.weparty.module.message.Message
 import com.adealink.weparty.module.operation.Operation
-import com.adealink.weparty.module.operation.newuser.HomeBannerEntranceFloatViewComp
+import com.adealink.weparty.module.task.UserTaskManager
+import com.adealink.weparty.module.task.gotoUserTaskCenter
 import com.adealink.weparty.ui.home.util.HomeUIUtil
 
 /**
@@ -48,15 +54,25 @@ enum class HomeRightBottomFloatViewType(val type: Int) {
     NEW_USER_LOTTERY(2),//新用户抽奖
     DayRecharge(3), //每日充值福利
     FirstRecharge(4), //首充
+    TASK_CENTER_COUNT_DOWN(5), //任务中心限时引导
+}
+
+sealed class BannerItemData(val type: Int) {
+    data class TaskCenter(
+        val lastTime: Long,
+        val dotCount: Int
+    ) : BannerItemData(HomeRightBottomFloatViewType.TASK_CENTER_COUNT_DOWN.type)
+
+    object NewUserLottery : BannerItemData(HomeRightBottomFloatViewType.NEW_USER_LOTTERY.type)
+    object DayRecharge : BannerItemData(HomeRightBottomFloatViewType.DayRecharge.type)
+    object FirstRecharge : BannerItemData(HomeRightBottomFloatViewType.FirstRecharge.type)
 }
 
 class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
-    BaseDragFloatView(floatData) {
+    BaseLongPressDragFloatView(floatData) {
 
     private var binding: LayoutHomeBannerEntranceViewBinding? = null
 
-//    private val bannerAdapter by fastLazy { BannerViewAdapter(listOf()) }
-
     private val show: Boolean
         get() {
             //只在message tab展示或者私聊页展示
@@ -73,11 +89,7 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
         super.onCreate()
         val binding = LayoutHomeBannerEntranceViewBinding.inflate(LayoutInflater.from(context))
         this.binding = binding
-        binding.root.layoutParams = ViewGroup.LayoutParams(
-            ViewGroup.LayoutParams.MATCH_PARENT,
-            ViewGroup.LayoutParams.MATCH_PARENT
-        )
-        setContentView(binding.root)
+        setContentView(binding.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
 
         binding.bannerView.apply {
             setLoopTime(6 * 1000)
@@ -95,36 +107,32 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
     /**
      * 设置入口列表
      */
-    fun setEntranceList(list: List<Int>, emptyCallback: () -> Unit) {
+    fun setEntranceList(list: List<BannerItemData>, emptyCallback: () -> Unit) {
         val bannerAdapter = BannerViewAdapter(list)
         val bannerView = binding?.bannerView ?: return
         binding?.bannerView?.setAdapter(bannerAdapter)
         binding?.bannerView?.start()
-
-        binding?.bannerView?.onClick {
-            val currentItem = bannerView.currentItem
-            val realPos = bannerAdapter.getRealPosition(currentItem)
-            val fragmentActivity =
-                AppUtil.currentActivity as? FragmentActivity ?: return@onClick
-            when (list.getOrNull(realPos)) {
-                HomeRightBottomFloatViewType.NEW_USER_LOTTERY.type -> {
+        binding?.bannerView?.setOnBannerListener { bannerItemData, _ ->
+            val fragmentActivity = AppUtil.currentActivity as? FragmentActivity ?: return@setOnBannerListener
+            when (bannerItemData) {
+                is BannerItemData.NewUserLottery -> {
                     //新用户抽奖
                     val fragment =
                         Router.getRouterInstance<BaseDialogFragment>(Operation.NewUserLotteryDialog.PATH)
                             ?.apply {
 
                             }
-                    fragment?.show(fragmentActivity.supportFragmentManager,"NewUserLotteryDialog")
+                    fragment?.show(fragmentActivity.supportFragmentManager, "NewUserLotteryDialog")
                 }
 
-                HomeRightBottomFloatViewType.DayRecharge.type -> {
+                is BannerItemData.DayRecharge -> {
                     //日充值
                     val fragment =
                         Router.getRouterInstance<BaseDialogFragment>(Operation.RechargeDaily.PATH)
-                    fragment?.show(fragmentActivity.supportFragmentManager,"RechargeDaily")
+                    fragment?.show(fragmentActivity.supportFragmentManager, "RechargeDaily")
                 }
 
-                HomeRightBottomFloatViewType.FirstRecharge.type -> {
+                is BannerItemData.FirstRecharge -> {
                     //首充
                     Router.getRouterInstance<BaseDialogFragment>(Operation.RechargePackage.PATH)
                         ?.apply {
@@ -136,10 +144,14 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
                                     )
                                 }
                         }
-                        ?.show(fragmentActivity.supportFragmentManager,"RechargePackage")
+                        ?.show(fragmentActivity.supportFragmentManager, "RechargePackage")
                 }
-            }
 
+                is BannerItemData.TaskCenter -> {
+                    //跳转到任务中心
+                    gotoUserTaskCenter(fragmentActivity)
+                }
+            }
         }
 
         binding?.btnClose?.onClick {
@@ -157,6 +169,10 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
                 HomeRightBottomFloatViewType.FirstRecharge.type -> {
                     HomeBannerEntranceFloatViewComp.userCloseFirstRecharge = true
                 }
+
+                HomeRightBottomFloatViewType.TASK_CENTER_COUNT_DOWN.type -> {
+                    HomeBannerEntranceFloatViewComp.userCloseTaskCenterCountDown = true
+                }
             }
 
             removeEntrance(type, emptyCallback)
@@ -172,7 +188,7 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
         val bannerAdapter = binding?.bannerView?.adapter ?: return
         bannerAdapter as BannerViewAdapter
         val list = bannerAdapter.datas
-        val newList = list.filter { it != type }
+        val newList = list.filter { it.type != type }
         binding?.bannerView?.setDatas(newList)
         if (newList.isEmpty()) {
             gone()
@@ -181,26 +197,24 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
     }
 
     override fun getLayoutParamWidth(): Int {
-        return 78f.dp()
+        return 71.dp()
     }
 
     override fun getLayoutParamHeight(): Int {
-        return 88f.dp()
-    }
-
-    override fun getClickableViews(): List<View>? {
-        val clickBtn = binding?.bannerView ?: return null
-        val closeBtn = binding?.btnClose ?: return null
-        return listOf(closeBtn, clickBtn)
+        return 73.dp()
     }
 
     override fun getLayoutParamX(): Int {
-        return DisplayUtil.getScreenWidth() - getLayoutParamWidth()
+        return if (DisplayUtil.isRtlLayout()) {
+            0
+        } else {
+            DisplayUtil.getScreenWidth() - getLayoutParamWidth()
+        }
     }
 
     override fun getLayoutParamY(): Int {
         val homeTabHeight = 54.dp()
-        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 120.dp() - homeTabHeight
+        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 157.dp() - homeTabHeight
     }
 
     override fun applySnapToEdge(): Boolean {
@@ -212,12 +226,12 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
     }
 
 
-    inner class BannerViewAdapter(val list: List<Int>) :
-        BannerAdapter<Int, RecyclerView.ViewHolder>(list) {
+    inner class BannerViewAdapter(val list: List<BannerItemData>) :
+        BannerAdapter<BannerItemData, RecyclerView.ViewHolder>(list) {
 
         override fun getItemViewType(position: Int): Int {
             val realPos = getRealPosition(position)
-            return list.getOrNull(realPos) ?: -1
+            return list.getOrNull(realPos)?.type ?: -1
         }
 
         override fun onCreateHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
@@ -230,9 +244,9 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
                             false
                         )
                     ).apply {
-                        if (DisplayUtil.isRtlLayout()){
+                        if (DisplayUtil.isRtlLayout()) {
                             binding.svgaView.setAsset("ic_home_entrance_new_user_guide_ar.svga")
-                        }else{
+                        } else {
                             binding.svgaView.setAsset("ic_home_entrance_new_user_guide.svga")
                         }
                     }
@@ -261,13 +275,23 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
                     )
                 }
 
+                HomeRightBottomFloatViewType.TASK_CENTER_COUNT_DOWN.type -> {
+                    TaskCenterCountDownViewBinder(
+                        ItemHomeBannerEntranceTaskCenterCountDownViewBinding.inflate(
+                            LayoutInflater.from(parent.context),
+                            parent,
+                            false
+                        )
+                    )
+                }
+
                 else -> null
             }
         }
 
         override fun onBindView(
             holder: RecyclerView.ViewHolder?,
-            data: Int?,
+            data: BannerItemData,
             position: Int,
             size: Int
         ) {
@@ -282,6 +306,19 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
                     val binding = (holder as DayRechargeViewBinder).binding
 
                 }
+
+                HomeRightBottomFloatViewType.TASK_CENTER_COUNT_DOWN.type -> {
+                    val taskCenter = data as? BannerItemData.TaskCenter ?: return
+                    val taskCenterCountDownViewBinder = holder as? TaskCenterCountDownViewBinder ?: return
+                    taskCenterCountDownViewBinder.update(taskCenter.lastTime, taskCenter.dotCount)
+                }
+            }
+        }
+
+        override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
+            super.onViewRecycled(holder)
+            if (holder is TaskCenterCountDownViewBinder) {
+                holder.cleanup()
             }
         }
 
@@ -297,4 +334,56 @@ class HomeBannerEntranceFloatView(floatData: HomeBannerEntranceFloatData) :
     inner class FirstRechargeViewBinder(binding: ItemHomeBannerEntranceFirstRechargeViewBinding) :
         BindingViewHolder<ItemHomeBannerEntranceFirstRechargeViewBinding>(binding)
 
+    inner class TaskCenterCountDownViewBinder(binding: ItemHomeBannerEntranceTaskCenterCountDownViewBinding) :
+        BindingViewHolder<ItemHomeBannerEntranceTaskCenterCountDownViewBinding>(binding) {
+        private var countDownTimer: CountDownTimer? = null
+        fun update(lastTime: Long, dotCount: Int) {
+            if (lastTime > 0) {
+                if (countDownTimer == null) {
+                    countDownTimer = object : CountDownTimer(lastTime, ONE_SECOND) {
+                        override fun onTick(millisUntilFinished: Long) {
+                            setTimeText(
+                                time = formatTimestamp(millisUntilFinished),
+                            )
+
+                        }
+
+                        override fun onFinish() {
+                            UserTaskManager.newUserTaskTimeFinish()
+                        }
+                    }
+                }
+                countDownTimer?.start()
+            }
+            binding.redDot.show(dot = NumDot(dotCount))
+        }
+
+        fun setTimeText(time: String) {
+            binding.tvCountdown.text = time
+        }
+
+        fun cleanup() {
+            countDownTimer?.cancel()
+            countDownTimer = null
+        }
+
+        private fun formatTimestamp(milliseconds: Long): String {
+            val seconds = milliseconds / 1000
+            val days = seconds / (24 * 3600)
+            val hours = (seconds % (24 * 3600)) / 3600
+            val minutes = (seconds % 3600) / 60
+            val secs = seconds % 60
+
+            val sb = StringBuilder()
+
+            // 根据是否大于0来拼接天数和小时
+            if (days > 0) sb.append(String.format("%02dd:", days))
+            if (hours > 0 || days > 0) sb.append(String.format("%02dh:", hours))
+
+            // 分钟和秒必定显示
+            sb.append(String.format("%02dm:%02ds", minutes, secs))
+//        sb.append(String.format("%02dm", minutes))
+            return sb.toString()
+        }
+    }
 }

+ 20 - 9
app/src/main/java/com/adealink/weparty/module/operation/newuser/HomeBannerEntranceFloatViewComp.kt

@@ -10,9 +10,7 @@ import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
 import com.adealink.weparty.module.operation.OperationModule
 import com.adealink.weparty.module.profile.ProfileModule
 import com.adealink.weparty.module.profile.data.Gender
-import com.adealink.weparty.module.task.HomeBannerEntranceFloatData
-import com.adealink.weparty.module.task.HomeBannerEntranceFloatView
-import com.adealink.weparty.module.task.HomeRightBottomFloatViewType
+import com.adealink.weparty.module.task.UserTaskManager
 import kotlinx.coroutines.launch
 
 /**
@@ -28,6 +26,7 @@ class HomeBannerEntranceFloatViewComp(lifecycleOwner: LifecycleOwner) :
         var userCloseLottery = false
         var userCloseFirstRecharge = false
         var userCloseDayRecharge = false
+        var userCloseTaskCenterCountDown = false
     }
 
     private val TAG = "HomeBannerEntranceFloatViewComp"
@@ -57,6 +56,11 @@ class HomeBannerEntranceFloatViewComp(lifecycleOwner: LifecycleOwner) :
             updateEntranceList()
         }
 
+        // 任务中心
+        UserTaskManager.homeCountDownTask.observe(viewLifecycleOwner) {
+            updateEntranceList()
+        }
+
     }
 
     override fun onResume() {
@@ -67,20 +71,27 @@ class HomeBannerEntranceFloatViewComp(lifecycleOwner: LifecycleOwner) :
 
     private fun updateEntranceList() {
         lifecycleScope.launch {
-            val entranceList = mutableListOf<Int>()
+            val entranceList = mutableListOf<BannerItemData>()
             if (!userCloseLottery && canShowUserLotteryView()) {
-                entranceList.add(HomeRightBottomFloatViewType.NEW_USER_LOTTERY.type)
+                entranceList.add(BannerItemData.NewUserLottery)
             }
 
             //优先首充
             if (!userCloseFirstRecharge && canShowFirstRechargeView()) {
-                entranceList.add(HomeRightBottomFloatViewType.FirstRecharge.type)
+                entranceList.add(BannerItemData.FirstRecharge)
             } else if (!userCloseDayRecharge && canShowRechargeDailyView()) {
-                entranceList.add(HomeRightBottomFloatViewType.DayRecharge.type)
+                entranceList.add(BannerItemData.DayRecharge)
+            }
+
+            if (!userCloseTaskCenterCountDown) {
+                val data = UserTaskManager.homeCountDownTask.value
+                if (data != null && data.endTime > 0L) {
+                    entranceList.add(BannerItemData.TaskCenter(data.endTime, data.dotCount))
+                }
             }
 
             if (entranceList.isNotEmpty()) {
-                addFloatView(entranceList)
+                addFloatView()
                 floatView?.setEntranceList(entranceList) {
                     removeFloatView()
                 }
@@ -114,7 +125,7 @@ class HomeBannerEntranceFloatViewComp(lifecycleOwner: LifecycleOwner) :
         return true
     }
 
-    private fun addFloatView(entranceList: MutableList<Int>) {
+    private fun addFloatView() {
         Log.d(TAG, "addFloatView")
         runOnUiThread {
             if (floatView != null) {

+ 0 - 2
app/src/main/java/com/adealink/weparty/module/profile/PayToAddGIFDialog.kt

@@ -15,8 +15,6 @@ import kotlin.math.min
 class PayToAddGIFDialog : BaseDialogFragment(R.layout.fragment_edit_userinfo_theme_pay_to_add) {
     private val binding by viewBinding(FragmentEditUserinfoThemePayToAddBinding::bind)
 
-    override val canceledOnTouchOutside: Boolean = true
-
     /**
      * 点击确定
      */

+ 50 - 0
app/src/main/java/com/adealink/weparty/module/profile/decorate/data/UserDecorateData.kt

@@ -4,6 +4,19 @@ import android.os.Parcelable
 import com.adealink.frame.tceffect.TCEffectManager
 import com.adealink.weparty.effect.EffectAnimType
 import com.adealink.weparty.effect.EffectResource
+import com.adealink.weparty.module.game.data.DragonTigerEntrance
+import com.adealink.weparty.module.game.data.GameEntrance
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.game.data.GreedyBoxEntrance
+import com.adealink.weparty.module.game.data.GreedyPersonalEntrance
+import com.adealink.weparty.module.game.data.GreedyProEntrance
+import com.adealink.weparty.module.game.data.LuckyFruitEntrance
+import com.adealink.weparty.module.game.data.LuckyProEntrance
+import com.adealink.weparty.module.game.data.RussianRouletteEntrance
+import com.adealink.weparty.module.game.data.SlotEntrance
+import com.adealink.weparty.module.game.data.SlotProEntrance
+import com.adealink.weparty.module.game.data.TeenPattiEntrance
+import com.adealink.weparty.module.game.data.TexasCowboyEntrance
 import com.google.gson.annotations.GsonNullable
 import com.google.gson.annotations.Must
 import com.google.gson.annotations.SerializedName
@@ -42,6 +55,7 @@ enum class DecorType(val value: Int) {
     TEXAS_GAME(88), //texas cowboy游戏
     LUCKY_PRO_GAME(104), //旧水果机
     GREEDY_PRO_GAME(108), //新水果机
+    GREEDY_PERSONAL_GAME(174),//个人水果机
 
     MOMENT_BG(120), // moment背景卡
     CHAT_BUBBLE(121), //聊天气泡
@@ -70,6 +84,42 @@ enum class DecorType(val value: Int) {
         fun map(value: Int): DecorType? {
             return entries.find { it.value == value }
         }
+
+
+    }
+}
+
+fun DecorType.toGameEntranceType(): GameEntranceType? {
+    return when (this) {
+        DecorType.LUCKY_FRUIT_GAME -> GameEntranceType.LUCKY_FRUIT
+        DecorType.LUCKY_PRO_GAME -> GameEntranceType.LUCKY_PRO
+        DecorType.GREEDY_PRO_GAME -> GameEntranceType.GREEDY_PRO
+        DecorType.JACKPOT_GAME -> GameEntranceType.JACKPOT
+        DecorType.JACKPOT_SLOT_GAME -> GameEntranceType.JACKPOT_SLOT
+        DecorType.GREEDY_BOX_GAME -> GameEntranceType.GREEDY_BOX
+        DecorType.TEEN_PATTI_GAME -> GameEntranceType.TEEN_PATTI
+        DecorType.RUSSIAN_TURNTABLE_GAME -> GameEntranceType.RUSSIAN_ROULETTE
+        DecorType.TEXAS_GAME -> GameEntranceType.TEXAS_COWBOY
+        DecorType.DRAGON_TIGER_FIGHT_GAME -> GameEntranceType.DRAGON_TIGER_FIGHT
+        DecorType.GREEDY_PERSONAL_GAME -> GameEntranceType.GREEDY_PERSONAL
+        else -> null
+    }
+}
+
+fun DecorType.toGameEntrance(canceledOnTouchOutside: Boolean = true): GameEntrance? {
+    return when (this) {
+        DecorType.LUCKY_FRUIT_GAME -> LuckyFruitEntrance()
+        DecorType.LUCKY_PRO_GAME -> LuckyProEntrance()
+        DecorType.GREEDY_PRO_GAME -> GreedyProEntrance()
+        DecorType.JACKPOT_GAME -> SlotEntrance()
+        DecorType.JACKPOT_SLOT_GAME -> SlotProEntrance()
+        DecorType.GREEDY_BOX_GAME -> GreedyBoxEntrance()
+        DecorType.TEEN_PATTI_GAME -> TeenPattiEntrance()
+        DecorType.RUSSIAN_TURNTABLE_GAME -> RussianRouletteEntrance()
+        DecorType.TEXAS_GAME -> TexasCowboyEntrance()
+        DecorType.DRAGON_TIGER_FIGHT_GAME -> DragonTigerEntrance()
+        DecorType.GREEDY_PERSONAL_GAME -> GreedyPersonalEntrance(canceledOnTouchOutside)
+        else -> null
     }
 }
 

+ 14 - 13
app/src/main/java/com/adealink/weparty/module/room/data/RoomNotifyData.kt

@@ -68,7 +68,7 @@ enum class RoomNotifyType(val uri: String) {
     DRAGON_TIGER_FIGHT_REWARD_NOTIFY("DRAGON_TIGER_FIGHT_REWARD_NOTIFY"),
     RUSSIA_ROULETTE_REWARD_NOTIFY("RUSSIAN_TURNTABLE_REWARD_NOTIFY"),
     TEXAS_COWBOY_REWARD_NOTIFY("TEXAS_POKER_REWARD_NOTIFY"),
-
+    GREEDY_PERSONAL_REWARD_NOTIFY("PERSONAL_LOTTERY_REWARD_NOTIFY"),//greedy personal
 
     //    SVIP_GLOBAL_NOTIFY("URI_SVIP_GLOBAL_NOTIFY");   // SVIP 升级全服通知
     COMMON_LEVEL_CHANGE_NOTIFY("COMMON_LEVEL_CHANGE_NOTIFY"),
@@ -77,19 +77,20 @@ enum class RoomNotifyType(val uri: String) {
     URI_INVITE_TASK_REWARD_NOTIFY("URI_INVITE_TASK_REWARD_NOTIFY"); // 拉新活动相关奖励
 
     companion object {
-        fun getGameDecorTypeValue(uri: String): Int {
+        fun getGameDecorType(uri: String): DecorType {
             return when(uri) {
-                LuckyFruit.uri -> DecorType.LUCKY_FRUIT_GAME.value
-                Slot.uri -> DecorType.JACKPOT_GAME.value
-                SlotPro.uri -> DecorType.JACKPOT_SLOT_GAME.value
-                TEEN_PATTI_REWARD_NOTIFY.uri -> DecorType.TEEN_PATTI_GAME.value
-                GREEDY_PRO_NOTIFY.uri -> DecorType.GREEDY_PRO_GAME.value
-                NEW_GREEDY_PRO_REWARD_NOTIFY.uri -> DecorType.LUCKY_PRO_GAME.value
-                GREEDY_BOX_NOTIFY.uri -> DecorType.GREEDY_BOX_GAME.value
-                DRAGON_TIGER_FIGHT_REWARD_NOTIFY.uri -> DecorType.DRAGON_TIGER_FIGHT_GAME.value
-                RUSSIA_ROULETTE_REWARD_NOTIFY.uri -> DecorType.RUSSIAN_TURNTABLE_GAME.value
-                TEXAS_COWBOY_REWARD_NOTIFY.uri -> DecorType.TEXAS_GAME.value
-                else -> -1
+                LuckyFruit.uri -> DecorType.LUCKY_FRUIT_GAME
+                Slot.uri -> DecorType.JACKPOT_GAME
+                SlotPro.uri -> DecorType.JACKPOT_SLOT_GAME
+                TEEN_PATTI_REWARD_NOTIFY.uri -> DecorType.TEEN_PATTI_GAME
+                GREEDY_PRO_NOTIFY.uri -> DecorType.GREEDY_PRO_GAME
+                NEW_GREEDY_PRO_REWARD_NOTIFY.uri -> DecorType.LUCKY_PRO_GAME
+                GREEDY_BOX_NOTIFY.uri -> DecorType.GREEDY_BOX_GAME
+                DRAGON_TIGER_FIGHT_REWARD_NOTIFY.uri -> DecorType.DRAGON_TIGER_FIGHT_GAME
+                RUSSIA_ROULETTE_REWARD_NOTIFY.uri -> DecorType.RUSSIAN_TURNTABLE_GAME
+                TEXAS_COWBOY_REWARD_NOTIFY.uri -> DecorType.TEXAS_GAME
+                GREEDY_PERSONAL_REWARD_NOTIFY.uri -> DecorType.GREEDY_PERSONAL_GAME
+                else -> DecorType.EMPTY
             }
         }
     }

+ 2 - 0
app/src/main/java/com/adealink/weparty/module/room/datasource/local/RoomLocalService.kt

@@ -86,6 +86,8 @@ object RoomLocalService : TypeDelegationPrefs(
 
     var showGreedyBoxNew: Boolean by PrefUserKey("key_show_greedy_box_new", true)
 
+    var showGreedyPersonalNew: Boolean by PrefUserKey("key_show_greedy_personal_new", true)
+
     var gameId: Long by PrefUserKey("gameId", 0)
 
     var clickedRoomWeddingPrivilege: Boolean by PrefKey("key_clicked_room_wedding_privilege", false)

+ 5 - 0
app/src/main/java/com/adealink/weparty/module/task/Data.kt

@@ -171,3 +171,8 @@ const val ACTION_DAILY_MIC_SAME_ROOM = 12 //每日连续上麦时长分钟
 
 const val EXTRA_ROOM_ID = "extra_room_id"
 const val EXTRA_ON_MIC_TIME = "extra_on_mic_time"
+
+data class HomeTaskCountDownData(
+    val endTime: Long = 0L,
+    val dotCount: Int = 0,
+)

+ 1 - 1
app/src/main/java/com/adealink/weparty/module/task/HomeIncomeFloatView.kt

@@ -89,7 +89,7 @@ class HomeIncomeFloatView(floatData: HomeIncomeFloatData) : BaseDragFloatView(fl
 
     override fun getLayoutParamY(): Int {
         val homeTabHeight = 54.dp()
-        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 120.dp() - homeTabHeight
+        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 80.dp() - homeTabHeight
     }
 
     override fun applySnapToEdge(): Boolean {

+ 0 - 174
app/src/main/java/com/adealink/weparty/module/task/HomeTaskCountDownFloatView.kt

@@ -1,174 +0,0 @@
-package com.adealink.weparty.module.task
-
-import android.app.Activity
-import android.os.CountDownTimer
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import com.adealink.frame.dot.NumDot
-import com.adealink.frame.router.Router
-import com.adealink.frame.util.DisplayUtil
-import com.adealink.frame.util.ONE_SECOND
-import com.adealink.frame.util.onClick
-import com.adealink.weparty.AppModule
-import com.adealink.weparty.commonui.ext.dp
-import com.adealink.weparty.commonui.widget.floatview.data.FloatWindowType
-import com.adealink.weparty.commonui.widget.floatview.data.IWindowFloatData
-import com.adealink.weparty.commonui.widget.floatview.data.MODE_APPLICATION
-import com.adealink.weparty.commonui.widget.floatview.view.BaseDragFloatView
-import com.adealink.weparty.databinding.LayoutHomeTaskCountDownFloatViewBinding
-import com.adealink.weparty.module.family.Family
-import com.adealink.weparty.module.message.Message
-
-/**
- * 注册前3天:任务中心限时引导入口
- * Created by XiaoDongLin.
- * Date: 2025/3/25
- */
-
-class HomeTaskCountDownFloatData(
-    val endTime: Long = 0L,
-    val dotCount: Int = 0,
-) : IWindowFloatData {
-    override fun windowType(): FloatWindowType = FloatWindowType.HOME_TASK_COUNT_DOWN
-
-    override fun windowMode() = MODE_APPLICATION
-
-}
-
-class HomeTaskCountDownFloatView(floatData: HomeTaskCountDownFloatData) : BaseDragFloatView(floatData) {
-
-    private var binding: LayoutHomeTaskCountDownFloatViewBinding? = null
-    private var closeClick: (() -> Unit)? = null
-
-    private val show: Boolean
-        get() {
-            val activity = windowManager?.currentActivity?.get() ?: return false
-            return hashSetOf<String>(
-                Router.getClazz(AppModule.Main.PATH)?.name ?: "",
-                Router.getClazz(Message.Conversation.PATH)?.name ?: "",
-                Router.getClazz(Family.Home.PATH)?.name ?: "",
-            ).contains(activity.javaClass.name)
-        }
-
-    private var countDownTimer: CountDownTimer? = null
-
-
-    override fun onCreate() {
-        super.onCreate()
-        val binding = LayoutHomeTaskCountDownFloatViewBinding.inflate(LayoutInflater.from(context))
-        this.binding = binding
-        binding.root.layoutParams = ViewGroup.LayoutParams(
-            ViewGroup.LayoutParams.MATCH_PARENT,
-            ViewGroup.LayoutParams.MATCH_PARENT
-        )
-        setContentView(binding.root)
-
-        binding.btnClose.onClick {
-            closeClick?.invoke()
-        }
-
-
-        visibility = if (show) View.VISIBLE else View.GONE
-    }
-
-
-    override fun getLayoutParamWidth(): Int {
-        return DisplayUtil.dp2px(75f)
-    }
-
-    override fun getLayoutParamHeight(): Int {
-        return DisplayUtil.dp2px(82f)
-    }
-
-    override fun getClickableViews(): List<View>? {
-        val clickBtn = binding?.btnClose ?: return null
-        return listOf(clickBtn)
-    }
-
-    override fun getLayoutParamX(): Int {
-        return DisplayUtil.getScreenWidth() - getLayoutParamWidth()
-    }
-
-    override fun getLayoutParamY(): Int {
-        val homeTabHeight = 54.dp()
-        return DisplayUtil.getScreenHeight() - getLayoutParamHeight() - 210.dp() - homeTabHeight
-    }
-
-    override fun applySnapToEdge(): Boolean {
-        return true
-    }
-
-    fun setOnCloseClick(click: (() -> Unit)?) {
-        this.closeClick = click
-    }
-
-    override fun onDestroy() {
-        super.onDestroy()
-        this.closeClick = null
-    }
-
-    /**
-     * 剩余时间
-     */
-    fun setEndTime(lastTime: Long) {
-        if (countDownTimer == null) {
-            countDownTimer = object : CountDownTimer(lastTime, ONE_SECOND) {
-                override fun onTick(millisUntilFinished: Long) {
-                    setTimeText(
-                        time = formatTimestamp(millisUntilFinished),
-                    )
-
-                }
-
-                override fun onFinish() {
-                    hide()
-                    UserTaskManager.newUserTaskTimeFinish()
-                }
-            }
-        }
-        countDownTimer?.start()
-    }
-
-    fun setTimeText(time: String) {
-        binding?.tvCountdown?.text = time
-    }
-
-    fun setDotCount(count: Int) {
-        binding?.redDot?.show(dot = NumDot(count))
-    }
-
-    fun show() {
-        visibility = View.VISIBLE
-    }
-
-    fun hide() {
-        visibility = View.GONE
-    }
-
-    override fun onActivityChange(activity: Activity) {
-        super.onActivityChange(activity)
-        visibility = if (show) View.VISIBLE else View.GONE
-    }
-
-
-    private fun formatTimestamp(milliseconds: Long): String {
-        val seconds = milliseconds / 1000
-        val days = seconds / (24 * 3600)
-        val hours = (seconds % (24 * 3600)) / 3600
-        val minutes = (seconds % 3600) / 60
-        val secs = seconds % 60
-
-        val sb = StringBuilder()
-
-        // 根据是否大于0来拼接天数和小时
-        if (days > 0) sb.append(String.format("%02dd:", days))
-        if (hours > 0 || days > 0) sb.append(String.format("%02dh:", hours))
-
-        // 分钟和秒必定显示
-        sb.append(String.format("%02dm:%02ds", minutes, secs))
-//        sb.append(String.format("%02dm", minutes))
-        return sb.toString()
-    }
-
-}

+ 0 - 90
app/src/main/java/com/adealink/weparty/module/task/HomeTaskCountDownViewComp.kt

@@ -1,90 +0,0 @@
-package com.adealink.weparty.module.task
-
-import androidx.lifecycle.LifecycleOwner
-import com.adealink.frame.base.fastLazy
-import com.adealink.frame.log.Log
-import com.adealink.frame.mvvm.view.ViewComponent
-import com.adealink.frame.util.runOnUiThread
-import com.adealink.weparty.commonui.widget.floatview.FloatViewFactory
-import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
-import com.adealink.weparty.module.operation.OperationModule
-
-/**
- * Created by XiaoDongLin.
- * Date: 2025/3/25
- */
-
-class HomeTaskCountDownViewComp(lifecycleOwner: LifecycleOwner) : ViewComponent(lifecycleOwner) {
-
-    private val TAG = "HomeTaskCountDownViewCo"
-    private var floatView: HomeTaskCountDownFloatView? = null
-    private val floatViewFactory by fastLazy { FloatViewFactory() }
-
-    override fun onResume() {
-        super.onResume()
-
-        UserTaskManager.homeCountDownTask.observe(viewLifecycleOwner) { floatData ->
-            if (floatData == null || floatData.endTime <= 0L || floatData.dotCount == 0) {
-                floatView?.let {
-                    WindowManagerProxy.getWindowManager().removeView(it)
-                }
-            } else {
-                addFloatView(floatData.endTime - System.currentTimeMillis())
-                floatView?.setEndTime(floatData.endTime - System.currentTimeMillis())
-                floatView?.setDotCount(count = floatData.dotCount)
-            }
-        }
-    }
-
-    override fun onDestroy() {
-        super.onDestroy()
-        removeFloatView()
-    }
-
-    private fun removeFloatView() {
-        Log.d(TAG, "removeFloatView")
-        floatView?.let {
-            WindowManagerProxy.getWindowManager().removeView(it)
-        }
-        floatView = null
-    }
-
-
-    /**
-     * @param lastTime 剩余时间
-     */
-    private fun addFloatView(lastTime: Long) {
-        if (lastTime <= 0) {
-            return
-        }
-        Log.d(TAG, "addFloatView, lastTime:$lastTime")
-        runOnUiThread {
-            if (floatView != null) {
-                floatView?.show()
-                return@runOnUiThread
-            }
-            floatView = HomeTaskCountDownFloatView(HomeTaskCountDownFloatData())
-            floatView?.let {
-                WindowManagerProxy.getWindowManager().addView(it)
-            }
-
-            floatView?.setOnClickListener {
-                //跳转到任务中心
-                val act = activity ?: return@setOnClickListener
-                gotoUserTaskCenter(act)
-            }
-
-            floatView?.setOnCloseClick {
-                floatView?.let {
-                    WindowManagerProxy.getWindowManager().removeView(it)
-                }
-            }
-            floatView?.show()
-
-        }
-
-
-    }
-
-
-}

+ 4 - 4
app/src/main/java/com/adealink/weparty/module/task/UserTaskManager.kt

@@ -40,7 +40,7 @@ interface IUserTaskManager : IBaseFrame<IUserTaskListener> {
 
 
     //首页到计时入口
-    val homeCountDownTask: LiveData<HomeTaskCountDownFloatData?>
+    val homeCountDownTask: LiveData<HomeTaskCountDownData?>
 
     //首页钻石收益入口
     val homeIncomeTask: LiveData<HomeIncomeFloatData?>
@@ -109,7 +109,7 @@ object UserTaskManager : BaseFrame<IUserTaskListener>(), IUserTaskManager {
     }
 
     override val allTaskCodeConfig: ExtMutableLiveData<TaskConfig?> = ExtMutableLiveData()
-    override val homeCountDownTask: ExtMutableLiveData<HomeTaskCountDownFloatData?> =
+    override val homeCountDownTask: ExtMutableLiveData<HomeTaskCountDownData?> =
         ExtMutableLiveData()
     override val homeIncomeTask: ExtMutableLiveData<HomeIncomeFloatData?> = ExtMutableLiveData()
     override val personalProfileTask: ExtMutableLiveData<TaskItemReward?> = ExtMutableLiveData()
@@ -426,7 +426,7 @@ object UserTaskManager : BaseFrame<IUserTaskListener>(), IUserTaskManager {
                                         homeIncomeTask.postValue(HomeIncomeFloatData())
                                     } else {
                                         homeCountDownTask.postValue(
-                                            HomeTaskCountDownFloatData(
+                                            HomeTaskCountDownData(
                                                 endTime = config.newUserTime + System.currentTimeMillis(),
                                                 dotCount = notFinishCount,
                                             )
@@ -561,7 +561,7 @@ object UserTaskManager : BaseFrame<IUserTaskListener>(), IUserTaskManager {
     //Welcome弹窗消失,展示悬浮任务入口
     fun showWelcomeTaskFloatView(endTime: Long, dotCount: Int) {
         homeCountDownTask.postValue(
-            HomeTaskCountDownFloatData(
+            HomeTaskCountDownData(
                 endTime = endTime,
                 dotCount = dotCount,
             )

+ 9 - 1
app/src/main/java/com/adealink/weparty/module/webview/WebViewDialogFragmentBuilder.kt

@@ -3,6 +3,7 @@ package com.adealink.weparty.module.webview
 import android.os.Bundle
 import androidx.fragment.app.Fragment
 import com.adealink.frame.router.Router
+import com.adealink.weparty.commonui.dialogfragment.BaseDialogFragment
 import com.adealink.weparty.module.webview.Web.HalfScreen.Companion.EXTRA_HEIGHT
 import com.adealink.weparty.module.webview.Web.HalfScreen.Companion.EXTRA_TRANSPARENT
 import com.adealink.weparty.module.webview.data.OfflineH5GameInfo
@@ -16,6 +17,7 @@ class WebViewDialogFragmentBuilder {
     private var trans: Boolean = false
     private var loadingUrl: String? = null
     private var offlineH5GameInfo: OfflineH5GameInfo? = null
+    private var canceledOnTouchOutside: Boolean = true
 
     fun height(heightPx: Int): WebViewDialogFragmentBuilder {
         this.heightPx = heightPx
@@ -36,14 +38,20 @@ class WebViewDialogFragmentBuilder {
         return this
     }
 
+    fun canceledOnTouchOutside(canceledOnTouchOutside: Boolean): WebViewDialogFragmentBuilder {
+        this.canceledOnTouchOutside = canceledOnTouchOutside
+        return this
+    }
+
     fun build(): IWebViewDialogFragment? {
-        val fragment = Router.getRouterInstance<Fragment>(Web.HalfScreen.PATH)
+        val fragment = Router.getRouterInstance<BaseDialogFragment>(Web.HalfScreen.PATH)
         fragment?.arguments = Bundle().apply {
             putInt(EXTRA_HEIGHT, heightPx)
             putBoolean(EXTRA_TRANSPARENT, trans)
             putString(Web.Common.EXTRA_LOADING_URL, loadingUrl)
             putParcelable(Web.Common.EXTRA_OFFLINE_H5_GAME_INFO, offlineH5GameInfo)
         }
+        fragment?.canceledOnTouchOutside = canceledOnTouchOutside
         return fragment as? IWebViewDialogFragment
     }
 

+ 2 - 0
app/src/main/java/com/adealink/weparty/ui/MainStartUpFragment.kt

@@ -26,6 +26,7 @@ import com.adealink.weparty.module.emotion.EmotionModule
 import com.adealink.weparty.module.family.FamilyModule
 import com.adealink.weparty.module.game.GameModule
 import com.adealink.weparty.module.gift.GiftModule
+import com.adealink.weparty.module.headline.HeadlineModule
 import com.adealink.weparty.module.level.LevelModule
 import com.adealink.weparty.module.medal.MedalModule
 import com.adealink.weparty.module.message.MessageModule
@@ -139,6 +140,7 @@ class MainStartUpFragment : BaseFragment() {
         InviteRewardManager.init()
         RoomTaskMonitor.init()
         OperationModule.init()
+        HeadlineModule.init()
         OperationModule.checkSuperSupporterWhatsAppFillStatus()
         if (activity?.isUiValid()==true) {
             familyInfoViewModel?.getApplyJoinFamilyUnHandleNum()

+ 11 - 4
app/src/main/java/com/adealink/weparty/ui/home/BaseHomeFragment.kt

@@ -36,6 +36,7 @@ import com.adealink.weparty.module.anchor.data.AnchorMessageReplyCode
 import com.adealink.weparty.module.anchor.data.AnchorMessageTemplateBody
 import com.adealink.weparty.module.anchor.data.AnchorMessageTemplateType
 import com.adealink.weparty.module.anchor.data.AnchorMessageType
+import com.adealink.weparty.module.game.floatview.GameEntranceFloatViewComp
 import com.adealink.weparty.module.level.data.TAG_LEVEL
 import com.adealink.weparty.module.medal.MedalModule
 import com.adealink.weparty.module.medal.data.MedalData
@@ -45,11 +46,12 @@ import com.adealink.weparty.module.operation.Operation
 import com.adealink.weparty.module.operation.OperationModule
 import com.adealink.weparty.module.operation.newuser.HomeBannerEntranceFloatViewComp
 import com.adealink.weparty.module.profile.Profile
+import com.adealink.weparty.module.profile.ProfileModule
+import com.adealink.weparty.module.profile.data.Gender
 import com.adealink.weparty.module.room.Room
 import com.adealink.weparty.module.task.CommonActivityRewardDialogTask
 import com.adealink.weparty.module.task.DailySignInComp
 import com.adealink.weparty.module.task.HomeIncomeViewComp
-import com.adealink.weparty.module.task.HomeTaskCountDownViewComp
 import com.adealink.weparty.module.userlist.UserList
 import com.adealink.weparty.ui.IScrollManager
 import com.adealink.weparty.ui.home.util.HomeLocalService
@@ -94,6 +96,10 @@ abstract class BaseHomeFragment : BaseFragment, ITabManager {
         arguments?.getString(AppModule.Main.EXTRA_MAIN_SUB_TAB)
     }
 
+    private var homeBannerEntranceFloatViewComp: HomeBannerEntranceFloatViewComp? = null
+
+    private var gameEntranceFloatViewComp: GameEntranceFloatViewComp? = null
+
     abstract fun initTabs()
 
     @CallSuper
@@ -138,6 +144,7 @@ abstract class BaseHomeFragment : BaseFragment, ITabManager {
                     HomeLocalService.hasVisitMessageTab = true
                 }
                 homeBannerEntranceFloatViewComp?.onHomeTabChange()
+                gameEntranceFloatViewComp?.onHomeTabChange()
             }
 
             override fun onTabUnselected(tab: TabLayout.Tab?) {
@@ -162,9 +169,11 @@ abstract class BaseHomeFragment : BaseFragment, ITabManager {
     override fun initComponents() {
         super.initComponents()
         homeBannerEntranceFloatViewComp = HomeBannerEntranceFloatViewComp(this).also { it.attach() }
-        HomeTaskCountDownViewComp(this).attach()
         HomeIncomeViewComp(this).attach()
         DailySignInComp(this).attach()
+        if (ProfileModule.getMyUserInfo()?.gender == Gender.MALE.gender) {
+            gameEntranceFloatViewComp = GameEntranceFloatViewComp(this).also { it.attach() }
+        }
     }
 
     fun updateTabView(
@@ -186,8 +195,6 @@ abstract class BaseHomeFragment : BaseFragment, ITabManager {
 
     open fun onConfigureTab(tab: Tab, binding: LayoutMainTabNormalBinding) {}
 
-    private var homeBannerEntranceFloatViewComp: HomeBannerEntranceFloatViewComp? = null
-
     override fun observeViewModel() {
         super.observeViewModel()
         anchorViewModel?.anchorMessageLD?.observe(viewLifecycleOwner,

+ 1 - 0
app/src/main/java/com/adealink/weparty/url/H5Page.kt

@@ -30,6 +30,7 @@ enum class H5Page(val key: String) {
     DIAMOND("diamond"),
     PREFETCH("prefetch"),
     GAME_COINS_FAQ("game_coins_faq"),
+    GREEDY_PERSONAL("greedy_personal"),
     LUCKY_FRUIT("lucky_fruit"),
     SUPER_GIFT("super_gift"),
     SLOT("slot"),

+ 5 - 0
app/src/main/java/com/adealink/weparty/url/H5PageConfig.kt

@@ -79,6 +79,11 @@ val defaultLocalConfig = listOf(
         url = UrlConfig.luckyFruit,
         desc = "lucky_fruit"
     ),
+    H5PageConfig(
+        key = H5Page.GREEDY_PERSONAL.key,
+        url = UrlConfig.greedyPersonal,
+        desc = "greedy_personal"
+    ),
     H5PageConfig(
         key = H5Page.SUPER_GIFT.key,
         url = UrlConfig.superGift,

+ 5 - 0
app/src/main/java/com/adealink/weparty/url/UrlConfig.kt

@@ -253,4 +253,9 @@ object UrlConfig {
             AppBaseInfo.isProdEnv -> "https://web.yoki.chat/rank-board-reward?projectname=yoki-rank-board&hideAppBar=true"
             else -> "http://web-test.yoki.chat/rank-board-reward?projectname=yoki-rank-board&hideAppBar=true"
         }
+
+    internal val greedyPersonal = when {
+        isProdEnv -> "https://web.yoki.chat/index?projectname=yoki-greedy-personal&aspect_ratio=1.607"
+        else -> "http://web-test.yoki.chat/index?projectname=yoki-greedy-personal&aspect_ratio=1.607"
+    }
 }

binární
app/src/main/res/drawable-xhdpi/common_greedy_personal_ic.webp


+ 16 - 0
app/src/main/res/layout/item_game_entrance_float_view.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <com.adealink.frame.image.view.NetworkImageView
+        android:id="@+id/icon"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 2
app/src/main/res/layout/item_home_banner_entrance_day_recharge_view.xml

@@ -8,8 +8,6 @@
             android:id="@+id/recharge_daily_down_time_view"
             android:layout_width="65dp"
             android:layout_height="65dp"
-            android:layout_marginTop="10dp"
-            android:layout_marginEnd="6dp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toTopOf="parent"/>
 

+ 2 - 4
app/src/main/res/layout/item_home_banner_entrance_first_recharge_view.xml

@@ -11,10 +11,8 @@
         app:layout_constraintTop_toTopOf="parent">
 
         <androidx.appcompat.widget.AppCompatImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="15dp"
-            android:layout_marginEnd="6dp"
+            android:layout_width="65dp"
+            android:layout_height="65dp"
             android:src="@drawable/ic_home_entrance_first_recharge"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"

+ 0 - 2
app/src/main/res/layout/item_home_banner_entrance_lottery_view.xml

@@ -14,8 +14,6 @@
             android:id="@+id/svga_view"
             android:layout_width="65dp"
             android:layout_height="65dp"
-            android:layout_marginTop="15dp"
-            android:layout_marginEnd="6dp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"

+ 5 - 16
app/src/main/res/layout/layout_home_task_count_down_float_view.xml → app/src/main/res/layout/item_home_banner_entrance_task_center_count_down_view.xml

@@ -6,21 +6,19 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/cl_bg"
-        android:layout_width="wrap_content"
-        android:layout_height="80dp"
-        android:minWidth="65dp"
+        android:layout_width="65dp"
+        android:layout_height="65dp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent">
 
         <androidx.appcompat.widget.AppCompatImageView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="25dp"
             android:src="@drawable/home_icon_task_entrance"
+            android:layout_marginBottom="5dp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
-
+            app:layout_constraintBottom_toBottomOf="parent" />
 
         <com.adealink.weparty.commonui.widget.MediumTextView
             android:id="@+id/tv_countdown"
@@ -40,20 +38,11 @@
         <com.adealink.frame.dot.DotView
             android:id="@+id/red_dot"
             style="@style/CommonRedDot"
-            android:layout_marginTop="18dp"
+            android:layout_marginTop="4dp"
             android:layout_marginEnd="6dp"
             android:src="@drawable/home_icon_float_close"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
-
-        <androidx.appcompat.widget.AppCompatImageView
-            android:id="@+id/btn_close"
-            android:layout_width="16dp"
-            android:layout_height="16dp"
-            android:src="@drawable/home_icon_float_close"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
-
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 

+ 31 - 0
app/src/main/res/layout/layout_game_entrance_float_view.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:layout_height="75dp"
+    tools:layout_width="70dp">
+
+    <com.adealink.weparty.commonui.widget.banner.Banner
+        android:id="@+id/banner_view"
+        android:layout_width="65dp"
+        android:layout_height="65dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="6dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent">
+
+    </com.adealink.weparty.commonui.widget.banner.Banner>
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/btn_close"
+        android:layout_width="16dp"
+        android:layout_height="16dp"
+        android:src="@drawable/home_icon_float_close"
+        app:layout_constraintEnd_toEndOf="@id/banner_view"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 5 - 4
app/src/main/res/layout/layout_home_banner_entrance_view.xml

@@ -8,8 +8,10 @@
 
     <com.adealink.weparty.commonui.widget.banner.Banner
         android:id="@+id/banner_view"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
+        android:layout_width="65dp"
+        android:layout_height="65dp"
+        android:layout_marginEnd="6dp"
+        android:layout_marginTop="8dp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent">
 
@@ -19,8 +21,7 @@
         android:id="@+id/btn_close"
         android:layout_width="16dp"
         android:layout_height="16dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginEnd="6dp"
+        android:layout_marginEnd="5dp"
         android:src="@drawable/home_icon_float_close"
         android:visibility="gone"
         app:layout_constraintEnd_toEndOf="parent"

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -209,6 +209,7 @@
    <string name="common_jackpot_slot" translatable="false">Jackpot slot</string>
    <string name="common_greedy_box">Greedy Box</string>
    <string name="common_greedy_pro">Greedy Pro</string>
+   <string name="common_greedy_personal" translatable="false">Lucky 77</string>
    <string name="common_copy">Copy</string>
    <string name="common_skip">Skip</string>
    <string name="common_skip_after_second">Skip %1$ds</string>

+ 1 - 1
module/backpack/src/main/java/com/adealink/weparty/backpack/dialog/ReceiveCustomIdDialog.kt

@@ -32,7 +32,7 @@ class ReceiveCustomIdDialog : BaseDialogFragment(R.layout.dialog_receive_custom_
     private val binding by viewBinding(DialogReceiveCustomIdBinding::bind)
     private val backpackViewModel by activityViewModels<BackpackViewModel> { BackpackViewModelFactory() }
     override val fgTag: String = "ReceiveCustomIdDialog"
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     @BindExtra(Backpack.Common.EXTRA_GIFT_GOOD_ID)
     var giftGoodId: GiftGoodId? = null

+ 1 - 2
module/couple/src/main/java/com/adealink/weparty/couple/dialog/GuardUserDialog.kt

@@ -54,8 +54,7 @@ class GuardUserDialog : BaseDialogFragment(R.layout.dialog_guard_guard_user) {
 
     override val cancelable: Boolean
         get() = false
-    override val canceledOnTouchOutside: Boolean
-        get() = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 13 - 18
module/game/src/main/java/com/adealink/weparty/game/GameServiceImpl.kt

@@ -4,13 +4,12 @@ import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.ViewModelStoreOwner
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.spi.RegisterService
-import com.adealink.frame.util.PackageUtil
 import com.adealink.weparty.App
-import com.adealink.weparty.channel.getChannel
 import com.adealink.weparty.cocosgame.data.Game
 import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
 import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
 import com.adealink.weparty.game.datasource.remote.GameHttpService
+import com.adealink.weparty.game.manager.gameEntranceManager
 import com.adealink.weparty.game.manager.gameManager
 import com.adealink.weparty.game.miccharmpk.manager.micCharmPKManager
 import com.adealink.weparty.game.miccharmpk.viewmodel.MicCharmPKViewModel
@@ -27,8 +26,8 @@ import com.adealink.weparty.game.viewmodel.GameViewModelFactory
 import com.adealink.weparty.module.game.IGameService
 import com.adealink.weparty.module.game.data.CommonActivityRewardInfoReq
 import com.adealink.weparty.module.game.data.GameActivityRewardInfo
+import com.adealink.weparty.module.game.data.GameEntranceType
 import com.adealink.weparty.module.game.data.GameShowConfig
-import com.adealink.weparty.module.game.data.GameShowConfigReq
 import com.adealink.weparty.module.game.data.GameType
 import com.adealink.weparty.module.game.data.GetUserLevelInfoReq
 import com.adealink.weparty.module.game.data.ReceiveRewardReq
@@ -40,6 +39,7 @@ import com.adealink.weparty.module.game.viewmodel.IRedPacketViewModel
 import com.adealink.weparty.module.game.viewmodel.IRouletteViewModel
 import com.adealink.weparty.module.pk.PKModule
 import com.adealink.weparty.module.profile.ProfileModule
+import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.data.RedPacketInfo
 
 /**
@@ -78,22 +78,16 @@ class GameServiceImpl : IGameService {
         return rouletteManager.isShowRoulette(roomId)
     }
 
-    override suspend fun isGameShow(configTypes: List<Int>): Map<Int, GameShowConfig> {
-        return when (val result = gameHttpService.getGameShowInfo(
-            GameShowConfigReq(
-                configTypes,
-                PackageUtil.getVersionCode(),
-                getChannel()
-            )
-        )) {
-            is Rlt.Success -> {
-                result.data.data ?: hashMapOf()
-            }
+    override suspend fun getAllGameShowConfigs(): Map<DecorType, GameShowConfig> {
+        return gameEntranceManager.getAllGameShowConfigs()
+    }
 
-            is Rlt.Failed -> {
-                hashMapOf()
-            }
-        }
+    override suspend fun isGameShow(configTypes: List<DecorType>): Map<DecorType, GameShowConfig> {
+        return gameEntranceManager.getGameShowConfigs(configTypes)
+    }
+
+    override fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean) {
+        return gameEntranceManager.navigateToGame(gameType, canceledOnTouchOutside)
     }
 
     override suspend fun getActivityGameRewardInfo(req: CommonActivityRewardInfoReq): GameActivityRewardInfo? {
@@ -156,6 +150,7 @@ class GameServiceImpl : IGameService {
 
     override fun logout() {
         rocketManager.onLogout()
+        gameEntranceManager.onLogout()
     }
 
 

+ 17 - 0
module/game/src/main/java/com/adealink/weparty/game/datasource/local/GameLocalService.kt

@@ -0,0 +1,17 @@
+package com.adealink.weparty.game.datasource.local
+
+import android.content.Context
+import com.adealink.frame.storage.sp.TypeDelegationPrefs
+import com.adealink.frame.util.AppUtil
+import com.adealink.weparty.module.profile.ProfileModule
+
+object GameLocalService : TypeDelegationPrefs(
+    prefs = {
+        AppUtil.appContext.getSharedPreferences("pref_game", Context.MODE_PRIVATE)
+    },
+    userId = {
+        ProfileModule.getMyUid().toString()
+    }
+) {
+    var gameShowConfigMap: String by PrefUserKey("key_game_show_config_map", "")
+}

+ 249 - 0
module/game/src/main/java/com/adealink/weparty/game/manager/GameEntranceManager.kt

@@ -0,0 +1,249 @@
+package com.adealink.weparty.game.manager
+
+import android.util.Log
+import androidx.fragment.app.FragmentActivity
+import com.adealink.frame.base.CommonDataNullError
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.data.json.froJsonErrorNull
+import com.adealink.frame.data.json.toJsonErrorNull
+import com.adealink.frame.frame.BaseFrame
+import com.adealink.frame.frame.IListener
+import com.adealink.frame.game.TAG_GAME
+import com.adealink.frame.network.data.Res
+import com.adealink.frame.util.AppUtil
+import com.adealink.frame.util.DisplayUtil
+import com.adealink.frame.util.PackageUtil
+import com.adealink.weparty.App
+import com.adealink.weparty.channel.getChannel
+import com.adealink.weparty.commonui.toast.util.showToast
+import com.adealink.weparty.config.GameVersionConfig
+import com.adealink.weparty.config.GlobalConfigType
+import com.adealink.weparty.config.globalConfigManager
+import com.adealink.weparty.game.datasource.local.GameLocalService
+import com.adealink.weparty.game.datasource.remote.GameHttpService
+import com.adealink.weparty.module.game.data.GameAppVersionOldCanPlayGameError
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.game.data.GameShowConfig
+import com.adealink.weparty.module.game.data.GameShowConfigReq
+import com.adealink.weparty.module.profile.decorate.data.DecorType
+import com.adealink.weparty.module.webview.WebViewDialogFragmentBuilder
+import com.adealink.weparty.module.webview.data.OfflineH5GameInfo
+import com.adealink.weparty.url.H5Page
+import com.adealink.weparty.url.urlConfigService
+import com.adealink.weparty.util.goLocalLinkPage
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.util.concurrent.ConcurrentHashMap
+
+val gameEntranceManager: IGameEntranceManager by lazy { GameEntranceManager() }
+
+class GameEntranceManager : BaseFrame<IListener>(), IGameEntranceManager {
+    private companion object {
+        const val TAG = "GameShowConfigManager"
+        const val GET_GAME_SHOW_CONFIG_TIME_INTERVAL = 5 * 60 * 1000L
+    }
+
+    private val allGameDecorTypeList = listOf(
+        DecorType.LUCKY_FRUIT_GAME,
+        DecorType.JACKPOT_GAME,
+        DecorType.JACKPOT_SLOT_GAME,
+        DecorType.GREEDY_BOX_GAME,
+        DecorType.TEEN_PATTI_GAME,
+        DecorType.DRAGON_TIGER_FIGHT_GAME,
+        DecorType.RUSSIAN_TURNTABLE_GAME,
+        DecorType.TEXAS_GAME,
+        DecorType.LUCKY_PRO_GAME,
+        DecorType.GREEDY_PRO_GAME,
+        DecorType.GREEDY_PERSONAL_GAME
+    )
+
+    private val gameShowConfigMap =
+        froJsonErrorNull<HashMap<DecorType, GameShowConfig>>(GameLocalService.gameShowConfigMap)
+            ?: mutableMapOf()
+
+    private val fetchTimeMap = ConcurrentHashMap<DecorType, Long>()
+
+    private val gameHttpService by lazy { App.instance.networkService.getHttpService(GameHttpService::class.java) }
+
+    override suspend fun getAllGameShowConfigs(forceNet: Boolean): Map<DecorType, GameShowConfig> {
+        return getGameShowConfigs(allGameDecorTypeList, forceNet)
+    }
+
+    override suspend fun getGameShowConfig(configType: DecorType, forceNet: Boolean): GameShowConfig? {
+        if (forceNet || System.currentTimeMillis() - (fetchTimeMap[configType] ?: 0) > GET_GAME_SHOW_CONFIG_TIME_INTERVAL) {
+            val oneConfigList = listOf(configType)
+            val rlt = getGameShowConfigsRemote(oneConfigList)
+            if (rlt is Rlt.Success) {
+                fetchTimeMap[configType] = System.currentTimeMillis()
+            }
+        }
+        return gameShowConfigMap[configType]
+    }
+
+    override suspend fun getGameShowConfigs(configTypes: List<DecorType>, forceNet: Boolean): Map<DecorType, GameShowConfig> {
+        val configsToFetch = if (forceNet) {
+            configTypes
+        } else {
+            configTypes.filter {
+                System.currentTimeMillis() - (fetchTimeMap[it] ?: 0) > GET_GAME_SHOW_CONFIG_TIME_INTERVAL
+            }
+        }
+
+        if (configsToFetch.isNotEmpty()) {
+            val rlt = getGameShowConfigsRemote(configsToFetch)
+            if (rlt is Rlt.Success) {
+                val currentTime = System.currentTimeMillis()
+                configsToFetch.forEach {
+                    fetchTimeMap[it] = currentTime
+                }
+            }
+        }
+
+        return gameShowConfigMap.filterKeys { it in configTypes }
+    }
+
+    private suspend fun getGameShowConfigsRemote(configs: List<DecorType>): Rlt<Res<Map<Int, GameShowConfig>>> {
+        val rlt = gameHttpService.getGameShowInfo(
+            GameShowConfigReq(
+                configs.map { it.value },
+                PackageUtil.getVersionCode(),
+                getChannel()
+            )
+        )
+        if (rlt is Rlt.Success) {
+            val res = rlt.data.data ?: return Rlt.Failed(CommonDataNullError())
+            configs.onEach {
+                val gameShowConfig = res[it.value]
+                if (gameShowConfig != null) {
+                    gameShowConfigMap[it] = gameShowConfig
+                }
+            }
+            withContext(this.coroutineContext) {
+                GameLocalService.gameShowConfigMap = toJsonErrorNull(gameShowConfigMap) ?: ""
+            }
+        }
+        return rlt
+    }
+
+    override fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean) {
+        when (gameType) {
+            // h5游戏
+            GameEntranceType.LUCKY_FRUIT -> openLuckyFruit()
+            GameEntranceType.LUCKY_PRO -> openLuckyPro()
+            GameEntranceType.GREEDY_PRO -> openGreedyPro()
+            GameEntranceType.GREEDY_PERSONAL -> openGreedyPersonal(canceledOnTouchOutside)
+            GameEntranceType.JACKPOT -> openJackpot()
+
+            // cocos游戏
+            GameEntranceType.JACKPOT_SLOT -> openOfflineGame(GlobalConfigType.GLOBAL_JACKPOT_SLOT_VERSION_INFO, DecorType.JACKPOT_SLOT_GAME, 1340)
+            GameEntranceType.GREEDY_BOX -> openOfflineGame(GlobalConfigType.GLOBAL_GREEDYBOX_VERSION_INFO, DecorType.GREEDY_BOX_GAME, 761)
+            GameEntranceType.TEEN_PATTI -> openOfflineGame(GlobalConfigType.GLOBAL_TEENPATTI_VERSION_INFO, DecorType.TEEN_PATTI_GAME, 1170)
+            GameEntranceType.RUSSIAN_ROULETTE -> openOfflineGame(GlobalConfigType.GLOBAL_RUSSIAN_TURNTABLE_VERSION_INFO, DecorType.RUSSIAN_TURNTABLE_GAME, 1123)
+            GameEntranceType.TEXAS_COWBOY -> openOfflineGame(GlobalConfigType.GLOBAL_TEXAS_COWBOY_VERSION_INFO, DecorType.TEXAS_GAME, 1230)
+            GameEntranceType.DRAGON_TIGER_FIGHT -> openOfflineGame(GlobalConfigType.GLOBAL_DRAGON_TIGER_FIGHT_VERSION_INFO, DecorType.DRAGON_TIGER_FIGHT_GAME, 1070)
+
+            else -> {
+
+            }
+        }
+    }
+
+    override fun onLogout() {
+        fetchTimeMap.clear()
+        gameShowConfigMap.clear()
+    }
+
+    private fun openLuckyFruit() {
+        val activity = AppUtil.currentActivity ?: return
+        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_FRUIT))
+    }
+
+    private fun openLuckyPro() {
+        val activity = AppUtil.currentActivity ?: return
+        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_PRO))
+    }
+
+    private fun openGreedyPro() {
+        val activity = AppUtil.currentActivity ?: return
+        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_PRO))
+    }
+
+    private fun openGreedyPersonal(canceledOnTouchOutside: Boolean = true) {
+        val activity = AppUtil.currentActivity as? FragmentActivity ?: return
+        WebViewDialogFragmentBuilder()
+            .height(1205 * DisplayUtil.getScreenWidth() / 750)
+            .canceledOnTouchOutside(canceledOnTouchOutside)
+            .build()
+            ?.showUrl(activity.supportFragmentManager, urlConfigService.getH5Url(H5Page.GREEDY_PERSONAL))
+    }
+
+    private fun openJackpot() {
+        val activity = AppUtil.currentActivity as? FragmentActivity ?: return
+        WebViewDialogFragmentBuilder()
+            .height(1300 * DisplayUtil.getScreenWidth() / 750)
+            .build()
+            ?.showUrl(activity.supportFragmentManager, urlConfigService.getH5Url(H5Page.SLOT))
+    }
+
+    private fun openOfflineGame(
+        configType: GlobalConfigType,
+        decorType: DecorType,
+        heightInDesign: Int,
+    ) {
+        launch {
+            val (isValid, newVersion) = checkGameValid(configType)
+            if (!isValid) {
+                return@launch
+            }
+            val resourceUrl = newVersion?.resourceUrl
+            val needDownload = newVersion?.needDownload ?: true
+            showGameDialog(resourceUrl, needDownload, decorType, heightInDesign)
+        }
+    }
+
+    private fun showGameDialog(
+        offlineUrl: String?,
+        needDownload: Boolean,
+        decorType: DecorType,
+        heightInDesign: Int,
+        loadingUrl: String? = "",
+    ) {
+        val activity = AppUtil.currentActivity as? FragmentActivity ?: return
+        val heightInPixel = heightInDesign * DisplayUtil.getScreenWidth() / 750
+
+        WebViewDialogFragmentBuilder()
+            .height(heightInPixel)
+            .loadingUrl(loadingUrl)
+            .offlineGameInfo(OfflineH5GameInfo(offlineUrl, decorType.value, needDownload))
+            .build()
+            ?.showUrl(activity.supportFragmentManager, "")
+    }
+
+    private suspend fun checkGameValid(type: GlobalConfigType): Pair<Boolean, GameVersionConfig?> {
+        val newVersion = froJsonErrorNull(globalConfigManager.suspendGetConfig(type)?.firstOrNull(), GameVersionConfig::class.java)
+        return when (val rlt = globalConfigManager.checkGameValid(type)) {
+            is Rlt.Success -> {
+                Pair(true, newVersion)
+            }
+
+            is Rlt.Failed -> {
+                Log.e(TAG_GAME, "offline game check, rlt: ${rlt.error.msg}")
+                showToast(rlt.error.msg)
+
+                when (rlt.error) {
+                    is GameAppVersionOldCanPlayGameError -> {
+                        // App版本过旧,但仍可玩本地游戏
+                        // 标记为无需下载,并返回true
+                        newVersion?.needDownload = false
+                        Pair(true, newVersion)
+                    }
+
+                    else -> {
+                        // 其他错误,返回false
+                        Pair(false, newVersion)
+                    }
+                }
+            }
+        }
+    }
+}

+ 13 - 0
module/game/src/main/java/com/adealink/weparty/game/manager/IGameEntranceManager.kt

@@ -0,0 +1,13 @@
+package com.adealink.weparty.game.manager
+
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.game.data.GameShowConfig
+import com.adealink.weparty.module.profile.decorate.data.DecorType
+
+interface IGameEntranceManager {
+    suspend fun getGameShowConfig(configType: DecorType, forceNet: Boolean = false): GameShowConfig?
+    suspend fun getGameShowConfigs(configTypes: List<DecorType>, forceNet: Boolean = false): Map<DecorType, GameShowConfig>
+    suspend fun getAllGameShowConfigs(forceNet: Boolean = false): Map<DecorType, GameShowConfig>
+    fun navigateToGame(gameType: GameEntranceType, canceledOnTouchOutside: Boolean = true)
+    fun onLogout()
+}

+ 1 - 1
module/game/src/main/java/com/adealink/weparty/game/rocket/dialog/RocketUserRewardDialog.kt

@@ -49,7 +49,7 @@ class RocketUserRewardDialog : BaseDialogFragment(R.layout.dialog_rocket_user_re
 
     private val listAdapter by fastLazy { MultiTypeListAdapter<RocketRewardItemData>() }
 
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 8 - 34
module/game/src/main/java/com/adealink/weparty/game/viewmodel/GameViewModel.kt

@@ -5,29 +5,22 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.base.Rlt
-import com.adealink.frame.data.json.froJsonErrorNull
-import com.adealink.frame.game.TAG_GAME
 import com.adealink.frame.mvvm.livedata.OnceMutableLiveData
 import com.adealink.frame.mvvm.viewmodel.BaseViewModel
 import com.adealink.frame.network.data.Res
 import com.adealink.frame.util.PackageUtil.getVersionCode
 import com.adealink.weparty.App
-import com.adealink.weparty.commonui.toast.util.showToast
-import com.adealink.weparty.config.GameVersionConfig
-import com.adealink.weparty.config.GlobalConfigType
-import com.adealink.weparty.config.globalConfigManager
 import com.adealink.weparty.game.datasource.remote.GameHttpService
+import com.adealink.weparty.game.manager.gameEntranceManager
 import com.adealink.weparty.game.miccharmpk.manager.micCharmPKManager
-import com.adealink.weparty.module.game.GameModule
-import com.adealink.weparty.module.game.data.GameAppVersionOldCanPlayGameError
 import com.adealink.weparty.module.game.data.GamePlayConflictError
 import com.adealink.weparty.module.game.data.GameShowConfig
 import com.adealink.weparty.module.game.data.GameType
-import com.adealink.weparty.module.game.data.GameVersionNotMatchError
 import com.adealink.weparty.module.game.data.LuckyFruitShowRes
 import com.adealink.weparty.module.game.data.SlotConfigInfoRes
 import com.adealink.weparty.module.game.viewmodel.IGameViewModel
 import com.adealink.weparty.module.pk.PKModule
+import com.adealink.weparty.module.profile.decorate.data.DecorType
 import kotlinx.coroutines.launch
 import com.adealink.weparty.R as APP_R
 
@@ -77,37 +70,18 @@ class GameViewModel : BaseViewModel(), IGameViewModel {
         return liveData
     }
 
-    override fun isGameShow(configTypes: List<Int>): LiveData<Map<Int, GameShowConfig>> {
-        val liveData = OnceMutableLiveData<Map<Int, GameShowConfig>>()
+    override fun isGameShow(configTypes: List<DecorType>): LiveData<Map<DecorType, GameShowConfig>> {
+        val liveData = OnceMutableLiveData<Map<DecorType, GameShowConfig>>()
         viewModelScope.launch {
-            liveData.send(GameModule.isGameShow(configTypes))
+            liveData.send(gameEntranceManager.getGameShowConfigs(configTypes))
         }
         return liveData
     }
 
-    override fun checkGameValid(type: GlobalConfigType): LiveData<Pair<Boolean, GameVersionConfig?>> {
-        val liveData = MutableLiveData<Pair<Boolean, GameVersionConfig?>>()
+    override fun getAllGameShowConfigs(): LiveData<Map<DecorType, GameShowConfig>> {
+        val liveData = OnceMutableLiveData<Map<DecorType, GameShowConfig>>()
         viewModelScope.launch {
-            val newVersion = froJsonErrorNull(globalConfigManager.suspendGetConfig(type)?.firstOrNull(), GameVersionConfig::class.java)
-            when(val rlt = globalConfigManager.checkGameValid(type)) {
-                is Rlt.Success -> {
-                    liveData.send(Pair(true, newVersion))
-                }
-                is Rlt.Failed -> {
-                    Log.e(TAG_GAME, "offline game check, rlt: ${rlt.error.msg}")
-                    when(rlt.error) {
-                        is GameAppVersionOldCanPlayGameError -> {
-                            // 这种情况不应该更新游戏版本,只允许玩本地的版本
-                            newVersion?.needDownload = false
-                            liveData.send(Pair(true, newVersion))
-                        }
-                        else -> {
-                            liveData.send(Pair(false, newVersion))
-                        }
-                    }
-                    showToast(rlt.error.msg)
-                }
-            }
+            liveData.send(gameEntranceManager.getAllGameShowConfigs())
         }
         return liveData
     }

+ 1 - 1
module/gamehub/carrom/src/main/java/com/adealink/weparty/carrom/dialog/CarromGameResultDialog.kt

@@ -64,7 +64,7 @@ class CarromGameResultDialog : BaseDialogFragment(R.layout.dialog_carrom_game_re
     private val listAdapter by fastLazy { MultiTypeListAdapter<RankResult>() }
 
     override val cancelable: Boolean = false
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 1 - 1
module/gamehub/uno/src/main/java/com/adealink/weparty/uno/dialog/result/UnoGameResultDialog.kt

@@ -71,7 +71,7 @@ class UnoGameResultDialog : BaseDialogFragment(R.layout.dialog_uno_game_result),
     private val listAdapter by fastLazy { MultiTypeListAdapter<RankResult>() }
 
     override val cancelable: Boolean = false
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 1 - 1
module/gift/src/main/java/com/adealink/weparty/gift/luckygift/dialog/LuckGiftRewardDialog.kt

@@ -27,7 +27,7 @@ class LuckGiftRewardDialog : BaseDialogFragment(R.layout.fragment_lucky_gift_rew
     @BindExtra(name = Gift.LuckyGiftReward.EXTRA_LUCKY_GIFT_REWARD, desc = "")
     var rewardInfo: LuckyGiftLotteryNotify? = null
 
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 1 - 2
module/gift/src/main/java/com/adealink/weparty/gift/treasure/view/GrabTreasureGiftResultDialog.kt

@@ -61,8 +61,7 @@ class GrabTreasureGiftResultDialog : BaseDialogFragment(R.layout.dialog_grab_tre
         Router.bind(this)
     }
 
-    override val canceledOnTouchOutside: Boolean
-        get() = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun initViews() {
         super.initViews()

binární
module/headline/src/main/assets/headline_greedy_personal_global.svga


+ 10 - 0
module/headline/src/main/java/com/adealink/weparty/headline/HeadlineServiceImpl.kt

@@ -3,10 +3,15 @@ package com.adealink.weparty.headline
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.ViewModelStoreOwner
 import com.adealink.frame.spi.RegisterService
+import com.adealink.weparty.commonui.widget.floatview.data.IFloatData
+import com.adealink.weparty.commonui.widget.floatview.view.BaseFloatView
+import com.adealink.weparty.headline.floatview.GreedyPersonalGlobalHeadlineFloatData
+import com.adealink.weparty.headline.floatview.GreedyPersonalGlobalHeadlineFloatView
 import com.adealink.weparty.module.headline.listener.IHeadlineListener
 import com.adealink.weparty.headline.manager.headlineManager
 import com.adealink.weparty.headline.viewmodel.HeadlineViewModel
 import com.adealink.weparty.headline.viewmodel.HeadlineViewModelFactory
+import com.adealink.weparty.module.game.GameModule
 import com.adealink.weparty.module.headline.viewmodel.IHeadlineViewModel
 import com.adealink.weparty.module.headline.IHeadlineService
 
@@ -20,6 +25,11 @@ class HeadlineServiceImpl: IHeadlineService {
         return ViewModelProvider(owner, HeadlineViewModelFactory())[HeadlineViewModel::class.java]
     }
 
+
+    override fun getGreedyPersonalGlobalHeadlineFloatView(data: IFloatData): BaseFloatView<out IFloatData>? {
+        return GreedyPersonalGlobalHeadlineFloatView(data as GreedyPersonalGlobalHeadlineFloatData)
+    }
+
     override fun addListener(l: IHeadlineListener) {
         headlineManager.addListener(l)
     }

+ 13 - 0
module/headline/src/main/java/com/adealink/weparty/headline/floatview/GreedyPersonalGlobalHeadlineFloatData.kt

@@ -0,0 +1,13 @@
+package com.adealink.weparty.headline.floatview
+
+import com.adealink.weparty.commonui.widget.floatview.data.FloatWindowType
+import com.adealink.weparty.commonui.widget.floatview.data.IWindowFloatData
+import com.adealink.weparty.commonui.widget.floatview.data.MODE_APPLICATION
+import com.adealink.weparty.module.room.data.GlobalRoomBroadcastNotify
+import com.adealink.weparty.module.room.data.LotteryRewardNotify
+
+class GreedyPersonalGlobalHeadlineFloatData(val notify: LotteryRewardNotify) : IWindowFloatData {
+    override fun windowType(): FloatWindowType = FloatWindowType.GREEDY_PERSONAL_GLOBAL_HEADLINE
+
+    override fun windowMode() = MODE_APPLICATION
+}

+ 84 - 0
module/headline/src/main/java/com/adealink/weparty/headline/floatview/GreedyPersonalGlobalHeadlineFloatView.kt

@@ -0,0 +1,84 @@
+package com.adealink.weparty.headline.floatview
+
+import android.annotation.SuppressLint
+import android.graphics.PixelFormat
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.WindowManager
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.router.Router
+import com.adealink.frame.util.DisplayUtil
+import com.adealink.weparty.commonui.ext.dp
+import com.adealink.weparty.commonui.widget.floatview.view.BaseWindowFloatView
+import com.adealink.weparty.headline.view.GreedyPersonalGlobalHeadline
+import com.adealink.weparty.module.account.Account
+import com.adealink.weparty.module.headline.listener.IHeadlineOpListener
+import com.adealink.weparty.module.room.Room
+import com.adealink.weparty.module.room.data.RoomNotifyType
+import com.adealink.weparty.module.webview.Web
+
+@SuppressLint("ViewConstructor")
+class GreedyPersonalGlobalHeadlineFloatView(private val data: GreedyPersonalGlobalHeadlineFloatData) : BaseWindowFloatView(data) {
+
+    private val show: Boolean
+        get() {
+            return windowManager?.currentActivity?.get()
+                ?.let { !DISMISS_ACTIVITIES.contains(it.javaClass.name) }
+                ?: false
+        }
+
+    private val greedyPersonalGlobalHeadline by fastLazy {
+        GreedyPersonalGlobalHeadline(context).apply {
+            headlineOpListener = object : IHeadlineOpListener {
+                override fun onHeadlineRightBtnClick(type: RoomNotifyType?, params: Bundle?) {
+                    removeSelf("")
+                }
+            }
+        }
+    }
+
+    private var screenWidth = DisplayUtil.getScreenWidth()
+
+    override fun onCreate() {
+        super.onCreate()
+        val transX = when (DisplayUtil.isRtlLayout()) {
+            true -> -screenWidth.toFloat()
+            else -> screenWidth.toFloat()
+        }
+        setContentView(greedyPersonalGlobalHeadline)
+        visibility = if (show) View.VISIBLE else View.GONE
+        translationX = transX
+        greedyPersonalGlobalHeadline.updateUI(data.notify)
+        animate().translationX(0f).setDuration(300).withEndAction {
+            animate().setDuration(5000).withEndAction {
+                animate().translationX(-transX).setDuration(300).withEndAction {
+                    removeSelf("")
+                }.start()
+            }.start()
+        }.start()
+    }
+
+    override val windowParams = WindowManager.LayoutParams().apply {
+        width = getLayoutParamWidth()
+        height = getLayoutParamHeight()
+        format = PixelFormat.TRANSLUCENT
+        flags =
+            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+        gravity = Gravity.START or Gravity.TOP
+        x = 0
+        y = 32.dp()
+    }
+
+    private fun getLayoutParamWidth(): Int = screenWidth
+
+    private fun getLayoutParamHeight(): Int = 98.dp()
+
+    companion object {
+        private val DISMISS_ACTIVITIES = hashSetOf<String>().apply {
+            Router.getClazz(Room.Room.PATH)?.let { this.add(it.name) }
+            Router.getClazz(Account.Login.PATH)?.let { this.add(it.name) }
+            Router.getClazz(Web.BSFullScreen.PATH)?.let { this.add(it.name) }
+        }
+    }
+}

+ 15 - 314
module/headline/src/main/java/com/adealink/weparty/headline/fragment/HeadlineFragment.kt

@@ -27,7 +27,6 @@ import com.adealink.weparty.commonui.toast.util.showToast
 import com.adealink.weparty.commonui.widget.floatview.view.HideMode
 import com.adealink.weparty.commonui.widget.floatview.view.ITouchDispatchEventListener
 import com.adealink.weparty.commonui.widget.floatview.view.SwipeToTopConstraintLayout
-import com.adealink.weparty.config.GlobalConfigType
 import com.adealink.weparty.headline.R
 import com.adealink.weparty.headline.data.TAG_HEADLINE
 import com.adealink.weparty.headline.databinding.FragmentHealineBinding
@@ -36,7 +35,7 @@ import com.adealink.weparty.headline.effect.data.GlobalHeadlineEntity
 import com.adealink.weparty.headline.viewmodel.HeadlineViewModel
 import com.adealink.weparty.headline.viewmodel.HeadlineViewModelFactory
 import com.adealink.weparty.module.game.GameModule
-import com.adealink.weparty.module.game.data.GameShowConfig
+import com.adealink.weparty.module.game.data.GameEntranceType
 import com.adealink.weparty.module.game.rocket.effect.IHeadlineBtnClickListener
 import com.adealink.weparty.module.game.rocket.effect.RocketHeadlineEffectEntity
 import com.adealink.weparty.module.gift.Gift
@@ -47,7 +46,6 @@ import com.adealink.weparty.module.headline.Headline
 import com.adealink.weparty.module.headline.listener.IHeadlineOpListener
 import com.adealink.weparty.module.profile.Profile
 import com.adealink.weparty.module.profile.ProfileModule
-import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.Room
 import com.adealink.weparty.module.room.RoomModule
 import com.adealink.weparty.module.room.data.RoomMicMode
@@ -56,8 +54,6 @@ import com.adealink.weparty.module.room.listener.IRoomListener
 import com.adealink.weparty.module.room.wedding.IHeadlineClickListener
 import com.adealink.weparty.module.share.ShareModule
 import com.adealink.weparty.module.webview.Web
-import com.adealink.weparty.module.webview.WebViewDialogFragmentBuilder
-import com.adealink.weparty.module.webview.data.OfflineH5GameInfo
 import com.adealink.weparty.room.data.EnterRoomInfo
 import com.adealink.weparty.url.H5Page
 import com.adealink.weparty.url.urlConfigService
@@ -73,7 +69,6 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
     private val binding by viewBinding(FragmentHealineBinding::bind)
     private val headlineViewModel by viewModels<HeadlineViewModel> { HeadlineViewModelFactory() }
     private var isShowInviteRebate: Boolean? = null
-    private val gameShowConfigMap = hashMapOf<Int, GameShowConfig>()
 
     private val gameViewModel by fastLazy { GameModule.getGameViewModel(this) }
     private val giftViewModel by fastLazy { GiftModule.getGiftViewModel(this) }
@@ -298,22 +293,6 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
             val show = (it as? Rlt.Success)?.data?.data?.show
             isShowInviteRebate = (show == true)
         }
-        gameViewModel?.isGameShow(
-            listOf(
-                DecorType.LUCKY_FRUIT_GAME.value,
-                DecorType.JACKPOT_GAME.value,
-                DecorType.JACKPOT_SLOT_GAME.value,
-                DecorType.GREEDY_BOX_GAME.value,
-                DecorType.TEEN_PATTI_GAME.value,
-                DecorType.DRAGON_TIGER_FIGHT_GAME.value,
-                DecorType.RUSSIAN_TURNTABLE_GAME.value,
-                DecorType.TEXAS_GAME.value,
-                DecorType.LUCKY_PRO_GAME.value,
-                DecorType.GREEDY_PRO_GAME.value,
-            )
-        )?.observe(viewLifecycleOwner) { configMap ->
-                gameShowConfigMap.putAll(configMap)
-            }
 
         headlineViewModel.getHeadlineQueueRandomConfig().observe(viewLifecycleOwner) {
             if (it == null) {
@@ -349,148 +328,6 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
             .putExtra(Profile.Common.EXTRA_UID, uid).start()
     }
 
-    private fun checkAndShowLuckyFruitEntry() {
-        val luckyFruitShowConfig = gameShowConfigMap[DecorType.LUCKY_FRUIT_GAME.value]
-        if (luckyFruitShowConfig == null) {
-            gameViewModel?.isShowLuckyFruit()?.observe(viewLifecycleOwner) {
-                if (it is Rlt.Success) {
-                    showLuckyFruitEntry()
-                }
-            }
-        } else if (luckyFruitShowConfig.show) {
-            showLuckyFruitEntry()
-        }
-    }
-
-    private fun checkAndShowTeenPattiEntry() {
-        val teenPattiShowConfig = gameShowConfigMap[DecorType.TEEN_PATTI_GAME.value]
-        if (teenPattiShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.TEEN_PATTI_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.TEEN_PATTI_GAME.value]
-                    if (config?.show == true) {
-                        showTeenPattiEntry(config.loadingUrl)
-                    }
-                }
-        } else if (teenPattiShowConfig.show) {
-            showTeenPattiEntry(teenPattiShowConfig.loadingUrl)
-        }
-    }
-
-    private fun checkAndShowSlotProEntry() {
-        val slotProShowConfig = gameShowConfigMap[DecorType.JACKPOT_SLOT_GAME.value]
-        if (slotProShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.JACKPOT_SLOT_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.JACKPOT_SLOT_GAME.value]
-                    if (config?.show == true) {
-                        showSlotProEntry(config.loadingUrl)
-                    }
-                }
-        } else if (slotProShowConfig.show) {
-            showSlotProEntry(slotProShowConfig.loadingUrl)
-        }
-    }
-
-    private fun checkAndShowGreedyBoxEntry() {
-        val greedyBoxShowConfig = gameShowConfigMap[DecorType.GREEDY_BOX_GAME.value]
-        if (greedyBoxShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.GREEDY_BOX_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.GREEDY_BOX_GAME.value]
-                    if (config?.show == true) {
-                        showGreedyBoxEntry(config.loadingUrl)
-                    }
-                }
-        } else if (greedyBoxShowConfig.show) {
-            showGreedyBoxEntry(greedyBoxShowConfig.loadingUrl)
-        }
-    }
-
-    private fun checkAndShowGreedyProEntry() {
-        val greedyProShowConfig = gameShowConfigMap[DecorType.GREEDY_PRO_GAME.value]
-        if (greedyProShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.GREEDY_PRO_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.GREEDY_PRO_GAME.value]
-                    if (config?.show == true) {
-                        showGreedyProEntry()
-                    }
-                }
-        } else if (greedyProShowConfig.show) {
-            showGreedyProEntry()
-        }
-    }
-
-    private fun checkAndShowLuckyProEntry() {
-        val luckyProShowConfig = gameShowConfigMap[DecorType.LUCKY_PRO_GAME.value]
-        if (luckyProShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.LUCKY_PRO_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.LUCKY_PRO_GAME.value]
-                    if (config?.show == true) {
-                        showLuckyProEntry()
-                    }
-                }
-            return
-        } else if (luckyProShowConfig.show) {
-            showLuckyProEntry()
-        }
-    }
-
-    private fun checkAndShowDragonTigerEntry() {
-        val dragonTigerShowConfig = gameShowConfigMap[DecorType.DRAGON_TIGER_FIGHT_GAME.value]
-        if (dragonTigerShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.DRAGON_TIGER_FIGHT_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.DRAGON_TIGER_FIGHT_GAME.value]
-                    if (config?.show == true) {
-                        showDragonFightEntry(config.loadingUrl)
-                    }
-                }
-            return
-        } else if (dragonTigerShowConfig.show) {
-            showDragonFightEntry(dragonTigerShowConfig.loadingUrl)
-        }
-    }
-
-    private fun checkAndShowTexasCowboyEntry() {
-        val texasCowboyShowConfig = gameShowConfigMap[DecorType.TEXAS_GAME.value]
-        if (texasCowboyShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.TEXAS_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.TEXAS_GAME.value]
-                    if (config?.show == true) {
-                        showTexasCowboyEntry(config.loadingUrl)
-                    }
-                }
-            return
-        } else if (texasCowboyShowConfig.show) {
-            showTexasCowboyEntry(texasCowboyShowConfig.loadingUrl)
-        }
-    }
-
-    private fun checkAndShowRussianRouletteEntry() {
-        val russianRouletteShowConfig = gameShowConfigMap[DecorType.RUSSIAN_TURNTABLE_GAME.value]
-        if (russianRouletteShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.RUSSIAN_TURNTABLE_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.RUSSIAN_TURNTABLE_GAME.value]
-                    if (config?.show == true) {
-                        showRussianRouletteEntry(config.loadingUrl)
-                    }
-                }
-            return
-        } else if (russianRouletteShowConfig.show) {
-            showRussianRouletteEntry(russianRouletteShowConfig.loadingUrl)
-        }
-    }
-
-    private fun showLuckyFruitEntry() {
-        val activity = activity ?: return
-        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_FRUIT))
-    }
-
     private fun goSuperGiftWeb() {
         if (!GameModule.isShowSuperGift()) {
             showToast(R.string.headline_super_gift_level_limit)
@@ -503,146 +340,6 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
             .start()
     }
 
-    private fun checkAndShowSlotEntry() {
-        val jackpotShowConfig = gameShowConfigMap[DecorType.JACKPOT_GAME.value]
-        if (jackpotShowConfig == null) {
-            gameViewModel?.isGameShow(listOf(DecorType.JACKPOT_GAME.value))
-                ?.observe(viewLifecycleOwner) { configMap ->
-                    val config = configMap[DecorType.JACKPOT_GAME.value]
-                    if (config?.show == true) {
-                        goSlotWeb()
-                    }
-                }
-        } else if (jackpotShowConfig.show) {
-            goSlotWeb()
-        }
-    }
-
-    private fun goSlotWeb() {
-        val activity = activity ?: return
-        WebViewDialogFragmentBuilder()
-            .height(1300 * DisplayUtil.getScreenWidth() / 750)
-            .build()
-            ?.showUrl(activity.supportFragmentManager, urlConfigService.getH5Url(H5Page.SLOT))
-    }
-
-    private fun showSlotProEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_JACKPOT_SLOT_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1340 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.JACKPOT_SLOT_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showGreedyBoxEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_GREEDYBOX_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(761 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.GREEDY_BOX_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showDragonFightEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_DRAGON_TIGER_FIGHT_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1070 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.DRAGON_TIGER_FIGHT_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showTeenPattiEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_TEENPATTI_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1170 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.TEEN_PATTI_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showTexasCowboyEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_TEXAS_COWBOY_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1230 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.TEXAS_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showRussianRouletteEntry(loadingUrl: String?) {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_RUSSIAN_TURNTABLE_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if(it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1123 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(OfflineH5GameInfo(resourceUrl, DecorType.RUSSIAN_TURNTABLE_GAME.value, needDownload))
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showGreedyProEntry() {
-        val activity = activity ?: return
-        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.GREEDY_PRO))
-    }
-
-    private fun showLuckyProEntry() {
-        val activity = activity ?: return
-        goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_PRO))
-    }
-
-    /**
-     * svip全服升级通知点击,在房则进入房间,不在房间则进入个人主页
-     */
-    private fun onSvipLevelUpClick(roomId: Long, from: String, uid: Long) {
-        if (roomId > 0) {
-            enterRoomClick(roomId, from)
-        } else if (uid > 0) {
-            goUserProfile(uid)
-        }
-    }
-
     override fun onHeadlineRightBtnClick(type: RoomNotifyType?, params: Bundle?) {
         when (type) {
             RoomNotifyType.SendRedPacket, RoomNotifyType.SendGift -> {
@@ -663,43 +360,43 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
             }
 
             RoomNotifyType.LuckyFruit -> {
-                checkAndShowLuckyFruitEntry()
+                GameModule.navigateToGame(GameEntranceType.LUCKY_FRUIT)
             }
 
             RoomNotifyType.Slot -> {
-                checkAndShowSlotEntry()
+                GameModule.navigateToGame(GameEntranceType.JACKPOT)
             }
 
             RoomNotifyType.SlotPro -> {
-                checkAndShowSlotProEntry()
+                GameModule.navigateToGame(GameEntranceType.JACKPOT_SLOT)
             }
 
             RoomNotifyType.GREEDY_BOX_NOTIFY -> {
-                checkAndShowGreedyBoxEntry()
+                GameModule.navigateToGame(GameEntranceType.GREEDY_BOX)
             }
 
             RoomNotifyType.TEEN_PATTI_REWARD_NOTIFY -> {
-                checkAndShowTeenPattiEntry()
+                GameModule.navigateToGame(GameEntranceType.TEEN_PATTI)
             }
 
             RoomNotifyType.GREEDY_PRO_NOTIFY -> {
-                checkAndShowGreedyProEntry()
+                GameModule.navigateToGame(GameEntranceType.GREEDY_PRO)
             }
 
             RoomNotifyType.NEW_GREEDY_PRO_REWARD_NOTIFY -> {
-                checkAndShowLuckyProEntry()
+                GameModule.navigateToGame(GameEntranceType.LUCKY_PRO)
             }
 
             RoomNotifyType.DRAGON_TIGER_FIGHT_REWARD_NOTIFY -> {
-                checkAndShowDragonTigerEntry()
+                GameModule.navigateToGame(GameEntranceType.DRAGON_TIGER_FIGHT)
             }
 
             RoomNotifyType.RUSSIA_ROULETTE_REWARD_NOTIFY -> {
-                checkAndShowRussianRouletteEntry()
+                GameModule.navigateToGame(GameEntranceType.RUSSIAN_ROULETTE)
             }
 
             RoomNotifyType.TEXAS_COWBOY_REWARD_NOTIFY -> {
-                checkAndShowTexasCowboyEntry()
+                GameModule.navigateToGame(GameEntranceType.TEXAS_COWBOY)
             }
 
             RoomNotifyType.ADMIN_LOTTERY_ACTIVITY_REWARD_NOTIFY -> {
@@ -710,6 +407,10 @@ class HeadlineFragment : BaseFragment(R.layout.fragment_healine), IHeadlineOpLis
                     .start()
             }
 
+            RoomNotifyType.GREEDY_PERSONAL_REWARD_NOTIFY -> {
+                GameModule.navigateToGame(GameEntranceType.GREEDY_PERSONAL)
+            }
+
             else -> {
                 //ntd.
             }

+ 38 - 0
module/headline/src/main/java/com/adealink/weparty/headline/manager/HeadlineManager.kt

@@ -1,12 +1,18 @@
 package com.adealink.weparty.headline.manager
 
 import com.adealink.frame.base.Rlt
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.coroutine.dispatcher.Dispatcher
 import com.adealink.frame.frame.BaseFrame
 import com.adealink.frame.log.Log
 import com.adealink.frame.network.ISocketNotify
 import com.adealink.weparty.App
 import com.adealink.weparty.commonui.ext.onSuccess
+import com.adealink.weparty.commonui.widget.floatview.FloatViewFactory
+import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
 import com.adealink.weparty.headline.data.TAG_HEADLINE
+import com.adealink.weparty.headline.floatview.GreedyPersonalGlobalHeadlineFloatData
+import com.adealink.weparty.headline.floatview.GreedyPersonalGlobalHeadlineFloatView
 import com.adealink.weparty.module.gift.GiftModule
 import com.adealink.weparty.module.headline.listener.IHeadlineListener
 import com.adealink.weparty.module.profile.ProfileModule
@@ -14,13 +20,16 @@ import com.adealink.weparty.module.room.data.DailyRechargeRewardBroadcastNotify
 import com.adealink.weparty.module.room.data.GlobalRoomBroadcastNotify
 import com.adealink.weparty.module.room.data.InviteTaskRewardBroadcastNotify
 import com.adealink.weparty.module.room.data.LotteryActivityBroadcastNotify
+import com.adealink.weparty.module.room.data.LotteryRewardNotify
 import com.adealink.weparty.module.room.data.RoomNotifyType
 import kotlinx.coroutines.launch
 
 val headlineManager: IHeadlineManager by lazy { HeadlineManager() }
 
 class HeadlineManager : BaseFrame<IHeadlineListener>(), IHeadlineManager {
+    private val floatViewFactory by fastLazy { FloatViewFactory() }
 
+    //房间内横幅通知(给在房间的人发)
     private val roomGlobalHeadlineNotify = object : ISocketNotify<GlobalRoomBroadcastNotify> {
 
         override val uri: String = "GLOBAL_ROOM_BROADCAST"
@@ -34,6 +43,20 @@ class HeadlineManager : BaseFrame<IHeadlineListener>(), IHeadlineManager {
         }
     }
 
+    // 个人水果机横幅通知(只通知给自己,房间外显示)
+    private val greedyPersonalNotify = object : ISocketNotify<LotteryRewardNotify> {
+
+        override val uri: String = "URI_PERSONAL_LUCKY_FRUIT_PERSONAL_NOTIFY"
+
+        override fun needHandle(data: LotteryRewardNotify?): Boolean {
+            return data != null
+        }
+
+        override fun onNotify(data: LotteryRewardNotify) {
+            handleGreedyPersonalNotify(data)
+        }
+    }
+
     private val dailyRechargeRewardGlobalHeadlineNotify = object : ISocketNotify<DailyRechargeRewardBroadcastNotify> {
 
         override val uri: String = RoomNotifyType.DAILY_RECHARGE_REWARD_NOTIFY.uri
@@ -97,6 +120,7 @@ class HeadlineManager : BaseFrame<IHeadlineListener>(), IHeadlineManager {
 
     init {
         App.instance.networkService.subscribeNotify(roomGlobalHeadlineNotify)
+        App.instance.networkService.subscribeNotify(greedyPersonalNotify)
         App.instance.networkService.subscribeNotify(dailyRechargeRewardGlobalHeadlineNotify)
         App.instance.networkService.subscribeNotify(lotteryActivityRewardGlobalHeadlineNotify)
         App.instance.networkService.subscribeNotify(inviteTaskRewardNotify)
@@ -142,6 +166,7 @@ class HeadlineManager : BaseFrame<IHeadlineListener>(), IHeadlineManager {
                 }
 
                 else -> {
+                    //房间内横幅
                     dispatch {
                         it.onHeadlineNotify(notify)
                     }
@@ -150,6 +175,19 @@ class HeadlineManager : BaseFrame<IHeadlineListener>(), IHeadlineManager {
         }
     }
 
+    private fun handleGreedyPersonalNotify(notify: LotteryRewardNotify) {
+        //在房间外玩个人水果机需要在房间外也展示横幅给自己看
+        if (notify.rewardUid == ProfileModule.getMyUid()) {
+            launch(Dispatcher.UI) {
+                floatViewFactory.createFloatView<GreedyPersonalGlobalHeadlineFloatView>(
+                    GreedyPersonalGlobalHeadlineFloatData(notify)
+                )?.let {
+                    WindowManagerProxy.getWindowManager().addView(it)
+                }
+            }
+        }
+    }
+
     private suspend fun notifyCommonLevelChange(notify: GlobalRoomBroadcastNotify) {
         val commonLevelChangeNotify = notify.commonLevelChangeNotify ?: return
         val userInfo = commonLevelChangeNotify.userInfo ?: return

+ 53 - 0
module/headline/src/main/java/com/adealink/weparty/headline/view/GreedyPersonalGlobalHeadline.kt

@@ -0,0 +1,53 @@
+package com.adealink.weparty.headline.view
+
+import android.content.Context
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.style.ForegroundColorSpan
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import com.adealink.frame.aab.util.getCompatColor
+import com.adealink.frame.aab.util.getCompatString
+import com.adealink.frame.ext.safeSetSpan
+import com.adealink.weparty.headline.R
+import com.adealink.weparty.headline.databinding.LayoutLotteryCommonGlobalHeadlineBinding
+import com.adealink.weparty.module.headline.view.BaseHeadlineView
+import com.adealink.weparty.module.room.data.GlobalRoomBroadcastNotify
+import com.adealink.weparty.module.room.data.LotteryRewardNotify
+import com.adealink.weparty.module.room.data.RoomNotifyType
+import com.adealink.weparty.R as APP_R
+
+class GreedyPersonalGlobalHeadline @JvmOverloads constructor(
+    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0,
+) : BaseHeadlineView(context, attrs, defStyleAttr) {
+    private val binding =
+        LayoutLotteryCommonGlobalHeadlineBinding.inflate(LayoutInflater.from(context), this, true)
+
+    fun updateUI(notify: LotteryRewardNotify) {
+        binding.svgaBg.setAsset("headline_greedy_personal_global.svga")
+        binding.ivAvatar.setImageUrl(notify.rewardUidImgUrl)
+        binding.tvName.text = notify.rewardUidName
+        val rewardCoin = "${notify.rewardCoin}"
+        val desc = getCompatString(R.string.headline_greedy_personal_win, rewardCoin)
+        val descSb = SpannableStringBuilder(desc)
+        val rewardCoinIndex = desc.indexOf(rewardCoin)
+        descSb.safeSetSpan(
+            ForegroundColorSpan(getCompatColor(APP_R.color.color_FFFFEF29)),
+            rewardCoinIndex,
+            rewardCoinIndex +
+                    rewardCoin.length,
+            Spanned.SPAN_INCLUSIVE_EXCLUSIVE
+        )
+        binding.tvDesc.text = descSb
+        binding.btnPlay.setOnClickListener {
+            headlineOpListener?.onHeadlineRightBtnClick(RoomNotifyType.GREEDY_PERSONAL_REWARD_NOTIFY, null)
+        }
+    }
+
+    override fun updateUI(notify: GlobalRoomBroadcastNotify) {
+        if (notify.broadcastUri == RoomNotifyType.GREEDY_PERSONAL_REWARD_NOTIFY.uri) {
+            val lotteryRewardNotify = notify.lotteryRewardNotify ?: return
+            updateUI(lotteryRewardNotify)
+        }
+    }
+}

+ 3 - 0
module/headline/src/main/java/com/adealink/weparty/headline/view/HeadlineViewBuilder.kt

@@ -99,6 +99,9 @@ class HeadlineViewBuilder {
             RoomNotifyType.URI_INVITE_TASK_REWARD_NOTIFY.uri -> {
                 InviteTaskRewardGlobalHeadline(context)
             }
+            RoomNotifyType.GREEDY_PERSONAL_REWARD_NOTIFY.uri -> {
+                GreedyPersonalGlobalHeadline(context)
+            }
             else -> {
                 null
             }

+ 5 - 40
module/headline/src/main/java/com/adealink/weparty/headline/viewmodel/HeadlineViewModel.kt

@@ -1,7 +1,6 @@
 package com.adealink.weparty.headline.viewmodel
 
 import androidx.lifecycle.LiveData
-import com.adealink.frame.base.Rlt
 import com.adealink.frame.log.Log
 import com.adealink.frame.mvvm.livedata.ExtLiveData
 import com.adealink.frame.mvvm.livedata.ExtMutableLiveData
@@ -16,8 +15,6 @@ import com.adealink.weparty.module.headline.listener.IHeadlineListener
 import com.adealink.weparty.module.headline.viewmodel.IHeadlineViewModel
 import com.adealink.weparty.module.level.LevelModule
 import com.adealink.weparty.module.level.data.LevelType
-import com.adealink.weparty.module.profile.ProfileModule
-import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.RoomModule
 import com.adealink.weparty.module.room.data.GlobalRoomBroadcastNotify
 import com.adealink.weparty.module.room.data.GuardTreasureSuccessBroadcastNotify
@@ -33,33 +30,6 @@ class HeadlineViewModel : IHeadlineViewModel, BaseViewModel(), IHeadlineListener
         headlineManager.addListener(this)
     }
 
-    private val uri2LevelLimitMap = hashMapOf(
-        RoomNotifyType.LuckyFruit.uri to 3,
-        RoomNotifyType.Slot.uri to 3,
-        RoomNotifyType.SlotPro.uri to 3,
-        RoomNotifyType.GREEDY_BOX_NOTIFY.uri to 3,
-        RoomNotifyType.TEEN_PATTI_REWARD_NOTIFY.uri to 3,
-        RoomNotifyType.GREEDY_PRO_NOTIFY.uri to 3,
-        RoomNotifyType.NEW_SLOT_REWARD_NOTIFY.uri to 3,
-        RoomNotifyType.NEW_GREEDY_PRO_REWARD_NOTIFY.uri to 3,
-        RoomNotifyType.DRAGON_TIGER_FIGHT_REWARD_NOTIFY.uri to 3,
-        RoomNotifyType.RUSSIA_ROULETTE_REWARD_NOTIFY.uri to 3,
-        RoomNotifyType.TEXAS_COWBOY_REWARD_NOTIFY.uri to 3,
-    )
-
-    private val gameDecorTypeList = listOf(
-        DecorType.LUCKY_FRUIT_GAME.value,
-        DecorType.JACKPOT_GAME.value,
-        DecorType.JACKPOT_SLOT_GAME.value,
-        DecorType.GREEDY_BOX_GAME.value,
-        DecorType.TEEN_PATTI_GAME.value,
-        DecorType.DRAGON_TIGER_FIGHT_GAME.value,
-        DecorType.RUSSIAN_TURNTABLE_GAME.value,
-        DecorType.TEXAS_GAME.value,
-        DecorType.LUCKY_PRO_GAME.value,
-        DecorType.GREEDY_PRO_GAME.value
-    )
-
     override fun onHeadlineNotify(notify: GlobalRoomBroadcastNotify) {
         Log.i(TAG_ROOM_GLOBAL_BROADCAST, "onHeadlineNotify uri: ${notify.broadcastUri}")
         if (RoomModule.showHeadlineBroadcast(notify.broadcastUri).not()) {
@@ -97,18 +67,13 @@ class HeadlineViewModel : IHeadlineViewModel, BaseViewModel(), IHeadlineListener
             notify.broadcastUri == RoomNotifyType.TEXAS_COWBOY_REWARD_NOTIFY.uri ||
             notify.broadcastUri == RoomNotifyType.DRAGON_TIGER_FIGHT_REWARD_NOTIFY.uri ||
             notify.broadcastUri == RoomNotifyType.NEW_GREEDY_PRO_REWARD_NOTIFY.uri ||
-            notify.broadcastUri == RoomNotifyType.RUSSIA_ROULETTE_REWARD_NOTIFY.uri
+            notify.broadcastUri == RoomNotifyType.RUSSIA_ROULETTE_REWARD_NOTIFY.uri ||
+            notify.broadcastUri == RoomNotifyType.GREEDY_PERSONAL_REWARD_NOTIFY.uri
         ) {
             viewModelScope.launch {
-                val myUserInfoRlt = ProfileModule.getUserInfoByUid(ProfileModule.getMyUid(), true)
-                val gameConfigMap = GameModule.isGameShow(gameDecorTypeList)
-                if (myUserInfoRlt is Rlt.Success) {
-                    //水果机、Greedy Pro、slot全服头条只对3级及以上的人外显 TeenPatti全服头条只对5级及以上的人外显
-                    Log.i(TAG_ROOM_GLOBAL_BROADCAST, "userLevel: ${myUserInfoRlt.data.level}, showHeadLine: ${gameConfigMap[RoomNotifyType.getGameDecorTypeValue(notify.broadcastUri)]?.show}")
-                    if (myUserInfoRlt.data.getVipRechargeLevel() >= (uri2LevelLimitMap[notify.broadcastUri]
-                            ?: 0) && gameConfigMap[RoomNotifyType.getGameDecorTypeValue(notify.broadcastUri)]?.show == true) {
-                        globalHeadlineNotifyLD.send(notify, false)
-                    }
+                val gameConfigMap = GameModule.getAllGameShowConfigs()
+                if (gameConfigMap[RoomNotifyType.getGameDecorType(notify.broadcastUri)]?.show == true) {
+                    globalHeadlineNotifyLD.send(notify, false)
                 }
             }
         } else {

+ 2 - 2
module/headline/src/main/res/layout/layout_lottery_common_global_headline.xml

@@ -104,11 +104,11 @@
             android:id="@+id/iv_right_icon"
             android:layout_width="60dp"
             android:layout_height="60dp"
-            android:layout_marginTop="15dp"
             android:layout_marginEnd="4dp"
             android:src="@drawable/headline_coin_ic"
             app:layout_constraintEnd_toStartOf="@id/btn_play"
-            app:layout_constraintTop_toTopOf="parent" />
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 

+ 1 - 0
module/headline/src/main/res/values-ar/strings.xml

@@ -28,4 +28,5 @@
    <string name="headline_congratulate">تهانينا!</string>
    <string name="headline_congratulate_vip_upgrade_tips">على الترقية إلى VIP.LV%1$d</string>
    <string name="headline_invite_task_reward_desc">احصل على مكافآت من خلال الدعوات</string>
+   <string name="headline_greedy_personal_win">فاز عدد %s عملات ذهبية في Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-bn/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">ভাগ্যবান প্রো-এ %s কয়েন জিতেছে</string>
     <string name="headline_svip_level_up_tips">অভিনন্দন! SVIP%d-এ আপগ্রেড করার জন্য %s</string>
     <string name="headline_win">%2$s এ %1$s সোনার কয়েন জিতেছে</string>
+    <string name="headline_greedy_personal_win">Lucky77-এ %s কয়েন জিতেছে</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-es/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">gana %s monedas en lucky Pro</string>
     <string name="headline_svip_level_up_tips">¡Felicitar! %s en la actualización a SVIP%d</string>
     <string name="headline_win">Gana %1$s monedas de oro en %2$s</string>
+    <string name="headline_greedy_personal_win">gana %s monedas en Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-hi/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">लकी प्रो पर %s सिक्के जीतता है</string>
     <string name="headline_svip_level_up_tips">बधाई हो! SVIP%d में अपग्रेड पर %s</string>
     <string name="headline_win">%1$s सोने के सिक्के जीतता है %2$s में</string>
+    <string name="headline_greedy_personal_win">Lucky77 पर %s सिक्के जीते</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-in/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">memenangkan %s koin di lucky Pro</string>
     <string name="headline_svip_level_up_tips">Mengucapkan selamat! %s pada peningkatan ke SVIP%d</string>
     <string name="headline_win">Memenangkan %1$s koin emas di %2$s</string>
+    <string name="headline_greedy_personal_win">menang %s koin di Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-kk/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">бару</string>
     <string name="headline_svip_level_up_tips">Құттықтаймыз! %s SVIP%d деңгейіне көтерілгенімен</string>
     <string name="headline_win">%2$s-та %1$s алтын монета ұтады</string>
+    <string name="headline_greedy_personal_win">Lucky77 ойынында %s тиын ұтып алды</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-ky/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">кет</string>
     <string name="headline_svip_level_up_tips">Куттуктайм! %s SVIP%dге көтөрүлүшү менен</string>
     <string name="headline_win">%2$s\'да %1$s алтын тыйын утат</string>
+    <string name="headline_greedy_personal_win">Lucky77\'де %s тыйын утуп алды</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-ms/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">memenangi %s syiling di lucky Pro</string>
     <string name="headline_svip_level_up_tips">tahniah! %s pada peningkatan kepada SVIP%d</string>
     <string name="headline_win">Memenangi %1$s syiling emas dalam %2$s</string>
+    <string name="headline_greedy_personal_win">menang %s syiling di Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-pt/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">ganha %s moedas no Lucky Pro</string>
     <string name="headline_svip_level_up_tips">Felicitar! %s na atualização para SVIP%d</string>
     <string name="headline_win">Ganha %1$s moedas de ouro em %2$s</string>
+    <string name="headline_greedy_personal_win">ganha %s moedas no Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-ru/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">идти</string>
     <string name="headline_svip_level_up_tips">Поздравляем! %s с обновлением до SVIP%d</string>
     <string name="headline_win">Выигрывает %1$s золотых монет в %2$s</string>
+    <string name="headline_greedy_personal_win">выиграл(а) %s монет в Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-ta/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">போ</string>
     <string name="headline_svip_level_up_tips">வாழ்த்துகள்! %s SVIP%dக்கு மேம்படுத்தியதற்காக</string>
     <string name="headline_win">%2$s இல் %1$s தங்க நாணயங்களை வென்றார்</string>
+    <string name="headline_greedy_personal_win">Lucky77 இல் %s நாணயங்களை வென்றது</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-te/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">వెళ్ళు</string>
     <string name="headline_svip_level_up_tips">అభినందనలు! %s SVIP%dకి ప్రమోట్ అయినందుకు</string>
     <string name="headline_win">%2$s లో %1$s బంగారు నాణేలను గెలుచుకున్నారు</string>
+    <string name="headline_greedy_personal_win">Lucky77 లో %s నాణేలు గెలిచింది</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-tg/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">рафтан</string>
     <string name="headline_svip_level_up_tips">Табрик мекунем! %s бо такмили сатҳ ба SVIP%d</string>
     <string name="headline_win">Дар %2$s %1$s сиккаҳои тиллоӣ мебарад</string>
+    <string name="headline_greedy_personal_win">дар Lucky77 %s танга бурд кард</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-th/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">รับรางวัล %s เหรียญที่ Lucky Pro</string>
     <string name="headline_svip_level_up_tips">ขอแสดงความยินดี! %s ในการอัพเกรดเป็น SVIP%d</string>
     <string name="headline_win">ชนะ %1$s เหรียญทองใน %2$s</string>
+    <string name="headline_greedy_personal_win">ชนะ %s เหรียญที่ Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-tk/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">ket</string>
     <string name="headline_svip_level_up_tips">Gutlaýarys! %s SVIP%d derejäsi ýokarlandy</string>
     <string name="headline_win">%2$s-de %1$s altyn teňňe gazanýar</string>
+    <string name="headline_greedy_personal_win">Lucky77-de %s teňňe utdy</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-tl/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">nanalo ng %s coins sa lucky Pro</string>
     <string name="headline_svip_level_up_tips">batiin mo! %s sa pag-upgrade sa SVIP%d</string>
     <string name="headline_win">Nanalo ng %1$s gold coin sa %2$s</string>
+    <string name="headline_greedy_personal_win">nanalo ng %s barya sa Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-tr/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">lucky Pro\'da %s jeton kazandı</string>
     <string name="headline_svip_level_up_tips">Tebrikler! %s, SVIP%d\'ye yükseltiliyor</string>
     <string name="headline_win">%1$s altın madeni parayı %2$s\'de kazanır</string>
+    <string name="headline_greedy_personal_win">Lucky77\'de %s madeni para kazandı</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-ur/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">لکی پرو پر %s سکے جیتے۔</string>
     <string name="headline_svip_level_up_tips">مبارک ہو! %s کو SVIP میں اپ گریڈ کرنے پر%d</string>
     <string name="headline_win">%2$s میں %1$s سونے کے سکے جیتے۔</string>
+    <string name="headline_greedy_personal_win">Lucky77 پر %s سکے جیتے</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-uz/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_go">ket</string>
     <string name="headline_svip_level_up_tips">Tabriklaymiz! %s SVIP%d darajasiga oshgani bilan</string>
     <string name="headline_win">%2$s-da %1$s oltin tanga yutadi</string>
+    <string name="headline_greedy_personal_win">Lucky7\'da %s tanga yutib oldi</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-vi/strings.xml

@@ -25,4 +25,5 @@
     <string name="headline_lucky_pro_win">giành được %s xu tại Lucky Pro</string>
     <string name="headline_svip_level_up_tips">Xin chúc mừng! %s khi nâng cấp lên SVIP%d</string>
     <string name="headline_win">Thắng %1$s đồng tiền vàng trong %2$s</string>
+    <string name="headline_greedy_personal_win">thắng %s xu tại Lucky77</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-zh-rTW/strings.xml

@@ -24,4 +24,5 @@
     <string name="headline_lucky_pro_win">在 lucky Pro 中贏得 %s 個金幣</string>
     <string name="headline_win">在%2$s中贏得%1$s金幣</string>
     <string name="headline_svip_level_up_tips">祝賀! %s 升級至 SVIP%d</string>
+    <string name="headline_greedy_personal_win">在Lucky77贏得%s金幣</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values-zh/strings.xml

@@ -28,4 +28,5 @@
    <string name="headline_congratulate_vip_upgrade_tips">晋升为 VIP 等级 %1$d</string>
    <string name="headline_invite_task_reward_desc">通过邀请获得奖励</string>
    <string name="headline_greedy_pro">在 Greedy Pro 中赢得 %1$s 金币</string>
+    <string name="headline_greedy_personal_win">在Lucky77赢得%s金币</string>
 </resources>

+ 1 - 0
module/headline/src/main/res/values/strings.xml

@@ -28,4 +28,5 @@
    <string name="headline_congratulate">Congratulate!</string>
    <string name="headline_congratulate_vip_upgrade_tips">on the upgrade to VIP.LV%1$d</string>
    <string name="headline_invite_task_reward_desc">get rewards through invitations</string>
+   <string name="headline_greedy_personal_win">wins %s coins at Lucky77</string>
 </resources>

+ 2 - 1
module/medal/src/main/java/com/adealink/weparty/medal/MedalPreviewDialog.kt

@@ -18,6 +18,8 @@ import com.adealink.weparty.module.medal.Medal
 @RouterUri(path = [Medal.MedalPreview.PATH], desc = "勋章预览")
 class MedalPreviewDialog : BaseDialogFragment(R.layout.dialog_medal_preview) {
 
+    override var canceledOnTouchOutside: Boolean = false
+
     @BindExtra(name = Medal.Common.EXTRA_MEDAL_URL, desc = "勋章静态资源图")
     var medalUrl: String? = null
 
@@ -69,6 +71,5 @@ class MedalPreviewDialog : BaseDialogFragment(R.layout.dialog_medal_preview) {
         val window = dialog.window ?: return
         window.setLayout(DisplayUtil.dp2px(303f), WindowManager.LayoutParams.WRAP_CONTENT)
         window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
-        setCanceledOnTouchOutside(false)
     }
 }

+ 0 - 3
module/micgrab/src/main/java/com/adealink/weparty/micgrab/help/MicGrabRuleDialog.kt

@@ -24,9 +24,6 @@ class MicGrabRuleDialog : BaseDialogFragment(R.layout.dialog_mic_grab_help) {
 
     private val binding by viewBinding(DialogMicGrabHelpBinding::bind)
 
-    override val canceledOnTouchOutside: Boolean
-        get() = true
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         Router.bind(this)
         super.onViewCreated(view, savedInstanceState)

+ 0 - 3
module/micgrab/src/main/java/com/adealink/weparty/micgrab/result/MicGrabResultDialog.kt

@@ -54,9 +54,6 @@ class MicGrabResultDialog : BaseDialogFragment(R.layout.dialog_mic_grab_result),
 
     private var autoDismissEndTs: Long = 0L
 
-    override val canceledOnTouchOutside: Boolean
-        get() = true
-
     private val autoDismissUpdateRunnable = {
         val leftTs = autoDismissEndTs - System.currentTimeMillis()
         if (leftTs <= 0) {

+ 1 - 2
module/micgrab/src/main/java/com/adealink/weparty/micgrab/result/MicGrabResultFullScreenDialog.kt

@@ -64,8 +64,7 @@ class MicGrabResultFullScreenDialog : BaseDialogFragment(R.layout.fragment_mic_g
 
     private var autoDismissEndTs: Long = 0L
 
-    override val canceledOnTouchOutside: Boolean
-        get() = false
+    override var canceledOnTouchOutside: Boolean = false
 
     private val autoDismissUpdateRunnable = {
         val leftTs = autoDismissEndTs - System.currentTimeMillis()

+ 1 - 1
module/operation/src/main/java/com/adealink/weparty/operation/banner/BannerDialog.kt

@@ -27,7 +27,7 @@ class BannerDialog : BaseDialogFragment(R.layout.dialog_banner) {
     @BindExtra(name = Operation.BannerDialog.EXTRA_BANNERS)
     var banners: List<BannerInfo>? = null
 
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 1 - 1
module/operation/src/main/java/com/adealink/weparty/operation/rateapp/RateAppDialog.kt

@@ -30,7 +30,7 @@ import com.adealink.weparty.R as APP_R
 class RateAppDialog : BaseDialogFragment(R.layout.dialog_rate_app) {
     private val binding by viewBinding(DialogRateAppBinding::bind)
 
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     private val googleRateManager by fastLazy {
         ReviewManagerFactory.create(requireContext())

+ 1 - 1
module/pk/src/main/java/com/adealink/weparty/pk/dialog/RoomPKWinnerDialog.kt

@@ -34,7 +34,7 @@ class RoomPKWinnerDialog : BaseDialogFragment(R.layout.dialog_pk_winner) {
         dismiss()
     }
 
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)

+ 2 - 2
module/profile/src/main/java/com/adealink/weparty/profile/me/MeFragment.kt

@@ -557,9 +557,9 @@ class MeFragment : BaseFragment(R.layout.fragment_me), IScrollManager {
 
     private fun getAnchorCenterConfig() {
         lifecycleScope.launch {
-            val reqList = listOf(DecorType.ANCHOR_CENTER_CONFIG.value)
+            val reqList = listOf(DecorType.ANCHOR_CENTER_CONFIG)
             val showGameMap = GameModule.isGameShow(reqList)
-            if (showGameMap[DecorType.ANCHOR_CENTER_CONFIG.value]?.show == true) {
+            if (showGameMap[DecorType.ANCHOR_CENTER_CONFIG]?.show == true) {
                 binding.itemAnchorCenter.root.show()
                 MeTabStatEvent(CommonEventValue.Action.SHOW).apply {
                     btn to MeTabStatEvent.Btn.ANCHOR_ENTRANCE

+ 14 - 296
module/room/src/main/java/com/adealink/weparty/room/game/GameComp.kt

@@ -2,50 +2,25 @@ package com.adealink.weparty.room.game
 
 import android.annotation.SuppressLint
 import android.content.Intent
-import android.os.Bundle
 import android.view.View
-import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.LifecycleOwner
 import com.adealink.frame.base.fastLazy
-import com.adealink.frame.router.Router
-import com.adealink.frame.util.AppUtil
-import com.adealink.frame.util.DisplayUtil
-import com.adealink.weparty.commonui.dialogfragment.BaseDialogFragment
 import com.adealink.weparty.commonui.layout.DynamicLayers
 import com.adealink.weparty.commonui.layout.IDynamicView
-import com.adealink.weparty.config.GlobalConfigType
-import com.adealink.weparty.module.game.Game
 import com.adealink.weparty.module.game.GameModule
-import com.adealink.weparty.module.operation.Operation
-import com.adealink.weparty.module.operation.Operation.RechargePackage.Companion.EXTRA_SOURCE
-import com.adealink.weparty.module.operation.Operation.RechargePackage.Companion.SOURCE_ROOM_OPERATION
 import com.adealink.weparty.module.operation.OperationModule
 import com.adealink.weparty.module.operation.rechargepackage.data.EntranceType
-import com.adealink.weparty.module.profile.decorate.data.DecorType
 import com.adealink.weparty.module.room.RoomModule
 import com.adealink.weparty.module.room.base.BaseRoomComp
-import com.adealink.weparty.module.webview.WebViewDialogFragmentBuilder
-import com.adealink.weparty.module.webview.data.OfflineH5GameInfo
 import com.adealink.weparty.room.R
 import com.adealink.weparty.room.game.adapter.GameEntranceAdapter
-import com.adealink.weparty.room.game.data.DailyRechargeEntrance
-import com.adealink.weparty.room.game.data.DragonTigerEntrance
-import com.adealink.weparty.room.game.data.GameEntrance
-import com.adealink.weparty.room.game.data.GameEntranceType
-import com.adealink.weparty.room.game.data.GreedyBoxEntrance
-import com.adealink.weparty.room.game.data.GreedyProEntrance
-import com.adealink.weparty.room.game.data.LuckyFruitEntrance
-import com.adealink.weparty.room.game.data.LuckyProEntrance
-import com.adealink.weparty.room.game.data.RechargePackageEntrance
-import com.adealink.weparty.room.game.data.RocketEntrance
-import com.adealink.weparty.room.game.data.RussianRouletteEntrance
-import com.adealink.weparty.room.game.data.SlotEntrance
-import com.adealink.weparty.room.game.data.SlotProEntrance
-import com.adealink.weparty.room.game.data.TeenPattiEntrance
-import com.adealink.weparty.room.game.data.TexasCowboyEntrance
-import com.adealink.weparty.url.H5Page
-import com.adealink.weparty.url.urlConfigService
-import com.adealink.weparty.util.goLocalLinkPage
+import com.adealink.weparty.module.game.data.DailyRechargeEntrance
+import com.adealink.weparty.module.game.data.GameEntrance
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.game.data.RechargePackageEntrance
+import com.adealink.weparty.module.game.data.RocketEntrance
+import com.adealink.weparty.module.profile.decorate.data.toGameEntrance
+import com.adealink.weparty.module.profile.decorate.data.toGameEntranceType
 
 class GameComp(
     lifecycleOwner: LifecycleOwner,
@@ -63,7 +38,8 @@ class GameComp(
                     setIndicator(viewBinding.indicator, false)
                     setAdapter(gameEntranceAdapter)
                     setOnBannerListener { data, _ ->
-                        handleBannerClick(data)
+                        val gameEntrance = data as? GameEntrance ?: return@setOnBannerListener
+                        gameEntrance.onClick()
                     }
                 }
             }
@@ -120,166 +96,16 @@ class GameComp(
         }
     }
 
-    private fun showSlotPro(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_JACKPOT_SLOT_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1340 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.JACKPOT_SLOT_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showGreedyBox(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_GREEDYBOX_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(761 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.GREEDY_BOX_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showDragonFightEntry(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_DRAGON_TIGER_FIGHT_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1070 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.DRAGON_TIGER_FIGHT_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showTeenPattiEntry(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_TEENPATTI_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1170 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.TEEN_PATTI_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showTexasCowboyEntry(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_TEXAS_COWBOY_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1230 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.TEXAS_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showRussianRouletteEntry(loadingUrl: String? = "") {
-        gameViewModel?.checkGameValid(GlobalConfigType.GLOBAL_RUSSIAN_TURNTABLE_VERSION_INFO)
-            ?.observe(viewLifecycleOwner) {
-                if (it.first.not()) return@observe
-                val resourceUrl = it.second?.resourceUrl
-                val needDownload = it.second?.needDownload ?: true
-                val activity = activity ?: return@observe
-                WebViewDialogFragmentBuilder()
-                    .height(1123 * DisplayUtil.getScreenWidth() / 750)
-                    .loadingUrl(loadingUrl)
-                    .offlineGameInfo(
-                        OfflineH5GameInfo(
-                            resourceUrl,
-                            DecorType.RUSSIAN_TURNTABLE_GAME.value,
-                            needDownload
-                        )
-                    )
-                    .build()
-                    ?.showUrl(activity.supportFragmentManager, "")
-            }
-    }
-
-    private fun showRocketPanel() {
-        Router.getRouterInstance<BaseDialogFragment>(Game.Rocket.RocketPanel.PATH)
-            ?.show(fragmentManager)
-    }
-
     override fun loadData() {
         rechargePackageViewModel?.refreshConfig()
         dailyViewModel?.allowDailyRecharge()
-        gameViewModel?.isGameShow(
-            listOf(
-                DecorType.LUCKY_FRUIT_GAME.value,
-                DecorType.JACKPOT_GAME.value,
-                DecorType.JACKPOT_SLOT_GAME.value,
-                DecorType.GREEDY_BOX_GAME.value,
-                DecorType.TEEN_PATTI_GAME.value,
-                DecorType.DRAGON_TIGER_FIGHT_GAME.value,
-                DecorType.RUSSIAN_TURNTABLE_GAME.value,
-                DecorType.TEXAS_GAME.value,
-                DecorType.LUCKY_PRO_GAME.value,
-                DecorType.GREEDY_PRO_GAME.value
-            )
-        )?.observe(viewLifecycleOwner) { configMap ->
-            for ((key, value) in configMap) {
-                if (value.showInRoomActPps) {
-                    val entrance = getEntrance(key) ?: continue
+        gameViewModel?.getAllGameShowConfigs()?.observe(viewLifecycleOwner) { configMap ->
+            for ((decorType, gameShowConfig) in configMap) {
+                if (gameShowConfig.showInRoomActPps) {
+                    val entrance = decorType.toGameEntrance() ?: continue
                     addEntrance(entrance)
                 } else {
-                    val entranceType = getEntranceType(key) ?: continue
+                    val entranceType = decorType.toGameEntranceType() ?: continue
                     removeEntrance(entranceType)
                 }
             }
@@ -344,112 +170,4 @@ class GameComp(
             view.getViewBinding().banner.setCurrentItem(1, false)
         }
     }
-
-    private fun handleBannerClick(data: Any) {
-        when (data) {
-            is DailyRechargeEntrance -> {
-                val fragment =
-                    Router.getRouterInstance<BaseDialogFragment>(Operation.RechargeDaily.PATH)
-                val topActivity = AppUtil.currentActivity
-                if (topActivity is FragmentActivity) {
-                    fragment?.show(topActivity.supportFragmentManager)
-                }
-            }
-            is RechargePackageEntrance -> {
-                Router.getRouterInstance<BaseDialogFragment>(Operation.RechargePackage.PATH)
-                    ?.apply {
-                        arguments = Bundle()
-                            .apply {
-                                putInt(EXTRA_SOURCE, SOURCE_ROOM_OPERATION)
-                            }
-                    }
-                    ?.show(fragmentManager)
-            }
-
-            is LuckyFruitEntrance -> {
-                goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_FRUIT))
-            }
-
-            is SlotEntrance -> {
-                val activity = activity ?: return
-                WebViewDialogFragmentBuilder()
-                    .height(1300 * DisplayUtil.getScreenWidth() / 750)
-                    .build()
-                    ?.showUrl(
-                        activity.supportFragmentManager,
-                        urlConfigService.getH5Url(H5Page.SLOT)
-                    )
-            }
-
-            is GreedyProEntrance -> {
-                val activity = activity ?: return
-                goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.GREEDY_PRO))
-            }
-
-            is GreedyBoxEntrance -> {
-                showGreedyBox()
-            }
-
-            is SlotProEntrance -> {
-                showSlotPro()
-            }
-
-            is LuckyProEntrance -> {
-                val activity = activity ?: return
-                goLocalLinkPage(activity, urlConfigService.getH5Url(H5Page.LUCKY_PRO))
-            }
-
-            is TeenPattiEntrance -> {
-                showTeenPattiEntry()
-            }
-
-            is RussianRouletteEntrance -> {
-                showRussianRouletteEntry()
-            }
-
-            is TexasCowboyEntrance -> {
-                showTexasCowboyEntry()
-            }
-
-            is DragonTigerEntrance -> {
-                showDragonFightEntry()
-            }
-
-            is RocketEntrance -> {
-                showRocketPanel()
-            }
-        }
-    }
-
-    private fun getEntrance(id: Int): GameEntrance? {
-        return when (id) {
-            DecorType.LUCKY_FRUIT_GAME.value -> LuckyFruitEntrance()
-            DecorType.LUCKY_PRO_GAME.value -> LuckyProEntrance()
-            DecorType.GREEDY_PRO_GAME.value -> GreedyProEntrance()
-            DecorType.JACKPOT_GAME.value -> SlotEntrance()
-            DecorType.JACKPOT_SLOT_GAME.value -> SlotProEntrance()
-            DecorType.GREEDY_BOX_GAME.value -> GreedyBoxEntrance()
-            DecorType.TEEN_PATTI_GAME.value -> TeenPattiEntrance()
-            DecorType.RUSSIAN_TURNTABLE_GAME.value -> RussianRouletteEntrance()
-            DecorType.TEXAS_GAME.value -> TexasCowboyEntrance()
-            DecorType.DRAGON_TIGER_FIGHT_GAME.value -> DragonTigerEntrance()
-            else -> null
-        }
-    }
-
-    private fun getEntranceType(id: Int): GameEntranceType? {
-        return when (id) {
-            DecorType.LUCKY_FRUIT_GAME.value -> GameEntranceType.LUCKY_FRUIT
-            DecorType.LUCKY_PRO_GAME.value -> GameEntranceType.LUCKY_PRO
-            DecorType.GREEDY_PRO_GAME.value -> GameEntranceType.GREEDY_PRO
-            DecorType.JACKPOT_GAME.value -> GameEntranceType.SLOT
-            DecorType.JACKPOT_SLOT_GAME.value -> GameEntranceType.SLOT_PRO
-            DecorType.GREEDY_BOX_GAME.value -> GameEntranceType.GREEDY_BOX
-            DecorType.TEEN_PATTI_GAME.value -> GameEntranceType.TEEN_PATTI
-            DecorType.RUSSIAN_TURNTABLE_GAME.value -> GameEntranceType.RUSSIAN_ROULETTE
-            DecorType.TEXAS_GAME.value -> GameEntranceType.TEXAS_COWBOY
-            DecorType.DRAGON_TIGER_FIGHT_GAME.value -> GameEntranceType.DRAGON_TIGER_SLOT
-            else -> null
-        }
-    }
 }

+ 12 - 0
module/room/src/main/java/com/adealink/weparty/room/game/RoomGameCenterPanelFragment.kt

@@ -254,6 +254,10 @@ class RoomGameCenterPanelFragment : BottomDialogFragment(R.layout.fragment_room_
             RoomPlayCenterType.JACKPOT_SLOT -> {
                 goJackpotSlot(data.loadingUrl, data.url)
             }
+
+            RoomPlayCenterType.GREEDY_PERSONAL -> {
+                goGreedyPersonal()
+            }
             else -> {}
         }
     }
@@ -363,6 +367,14 @@ class RoomGameCenterPanelFragment : BottomDialogFragment(R.layout.fragment_room_
         dismiss()
     }
 
+    private fun goGreedyPersonal() {
+        WebViewDialogFragmentBuilder()
+            .height(1205 * DisplayUtil.getScreenWidth() / 750)
+            .build()
+            ?.showUrl(parentFragmentManager, urlConfigService.getH5Url(H5Page.GREEDY_PERSONAL))
+        dismiss()
+    }
+
     private fun goTigerMachine() {
         context?.let {
             Router.build(it, Web.FullScreen.PATH)

+ 20 - 18
module/room/src/main/java/com/adealink/weparty/room/game/adapter/GameEntranceAdapter.kt

@@ -9,21 +9,22 @@ import com.adealink.weparty.commonui.widget.banner.adapter.BannerAdapter
 import com.adealink.weparty.room.databinding.ItemDailyRechargeEntranceBinding
 import com.adealink.weparty.room.databinding.ItemGameEntranceBinding
 import com.adealink.weparty.room.databinding.ItemGameRocketEntranceBinding
-import com.adealink.weparty.room.game.data.DailyRechargeEntrance
-import com.adealink.weparty.room.game.data.DragonTigerEntrance
-import com.adealink.weparty.room.game.data.GameEntrance
-import com.adealink.weparty.room.game.data.GameEntranceType
-import com.adealink.weparty.room.game.data.GreedyBoxEntrance
-import com.adealink.weparty.room.game.data.GreedyProEntrance
-import com.adealink.weparty.room.game.data.LuckyFruitEntrance
-import com.adealink.weparty.room.game.data.LuckyProEntrance
-import com.adealink.weparty.room.game.data.RechargePackageEntrance
-import com.adealink.weparty.room.game.data.RocketEntrance
-import com.adealink.weparty.room.game.data.RussianRouletteEntrance
-import com.adealink.weparty.room.game.data.SlotEntrance
-import com.adealink.weparty.room.game.data.SlotProEntrance
-import com.adealink.weparty.room.game.data.TeenPattiEntrance
-import com.adealink.weparty.room.game.data.TexasCowboyEntrance
+import com.adealink.weparty.module.game.data.DailyRechargeEntrance
+import com.adealink.weparty.module.game.data.DragonTigerEntrance
+import com.adealink.weparty.module.game.data.GameEntrance
+import com.adealink.weparty.module.game.data.GameEntranceType
+import com.adealink.weparty.module.game.data.GreedyBoxEntrance
+import com.adealink.weparty.module.game.data.GreedyPersonalEntrance
+import com.adealink.weparty.module.game.data.GreedyProEntrance
+import com.adealink.weparty.module.game.data.LuckyFruitEntrance
+import com.adealink.weparty.module.game.data.LuckyProEntrance
+import com.adealink.weparty.module.game.data.RechargePackageEntrance
+import com.adealink.weparty.module.game.data.RocketEntrance
+import com.adealink.weparty.module.game.data.RussianRouletteEntrance
+import com.adealink.weparty.module.game.data.SlotEntrance
+import com.adealink.weparty.module.game.data.SlotProEntrance
+import com.adealink.weparty.module.game.data.TeenPattiEntrance
+import com.adealink.weparty.module.game.data.TexasCowboyEntrance
 
 /**
  * Created by sunxiaodong on 2021/8/2.
@@ -70,16 +71,17 @@ class GameEntranceAdapter(entrances: List<GameEntrance>) :
             is DailyRechargeEntrance -> GameEntranceType.DAILY_RECHARGE.type
             is RechargePackageEntrance -> GameEntranceType.RECHARGE_PACKAGE.type
             is LuckyFruitEntrance -> GameEntranceType.LUCKY_FRUIT.type
-            is SlotEntrance -> GameEntranceType.SLOT.type
+            is SlotEntrance -> GameEntranceType.JACKPOT.type
             is GreedyProEntrance -> GameEntranceType.GREEDY_PRO.type
             is GreedyBoxEntrance -> GameEntranceType.GREEDY_BOX.type
             is LuckyProEntrance -> GameEntranceType.LUCKY_PRO.type
-            is SlotProEntrance -> GameEntranceType.SLOT_PRO.type
+            is SlotProEntrance -> GameEntranceType.JACKPOT_SLOT.type
             is TeenPattiEntrance -> GameEntranceType.TEEN_PATTI.type
             is RussianRouletteEntrance -> GameEntranceType.RUSSIAN_ROULETTE.type
             is TexasCowboyEntrance -> GameEntranceType.TEXAS_COWBOY.type
-            is DragonTigerEntrance -> GameEntranceType.DRAGON_TIGER_SLOT.type
+            is DragonTigerEntrance -> GameEntranceType.DRAGON_TIGER_FIGHT.type
             is RocketEntrance -> GameEntranceType.ROCKET.type
+            is GreedyPersonalEntrance -> GameEntranceType.GREEDY_PERSONAL.type
         }
     }
 

+ 0 - 93
module/room/src/main/java/com/adealink/weparty/room/game/data/GameEntranceData.kt

@@ -1,93 +0,0 @@
-package com.adealink.weparty.room.game.data
-
-import com.adealink.frame.locale.language.languageManager
-import com.adealink.weparty.module.operation.rechargepackage.data.RechargePackageConfig
-import com.opensource.svgaplayer.utils.UriUtil
-
-/**
- * Created by sunxiaodong on 2021/8/2.
- */
-
-enum class GameEntranceType(val type: Int) {
-    LUCKY_FRUIT(0),
-    RECHARGE_PACKAGE(1),
-    SLOT(2),
-    DAILY_RECHARGE(3),
-    GREEDY_PRO(4),
-    LUCKY_PRO(6),
-    GREEDY_BOX(7),
-    SLOT_PRO(8),
-    TEEN_PATTI(10),
-    RUSSIAN_ROULETTE(11),
-    TEXAS_COWBOY(12),
-    DRAGON_TIGER_SLOT(13),
-    ROCKET(14),
-}
-
-sealed class GameEntrance(val icon: String, val type: GameEntranceType)
-
-
-class RechargePackageEntrance(val config: RechargePackageConfig) : GameEntrance(
-    config.getIcon(languageManager?.getLanguageCode()),
-    GameEntranceType.RECHARGE_PACKAGE
-)
-
-class DailyRechargeEntrance : GameEntrance(
-    "",
-    GameEntranceType.DAILY_RECHARGE
-)
-
-class LuckyFruitEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_lucky_fruit_ic).toString(),
-    GameEntranceType.LUCKY_FRUIT
-)
-
-class SlotEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_jackpot_ic).toString(),
-    GameEntranceType.SLOT
-)
-
-class GreedyProEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_greedy_pro_ic).toString(),
-    GameEntranceType.GREEDY_PRO
-)
-
-class GreedyBoxEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_greedy_box_ic).toString(),
-    GameEntranceType.GREEDY_BOX
-)
-
-class SlotProEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_jackpot_slot_ic).toString(),
-    GameEntranceType.SLOT_PRO
-)
-
-class LuckyProEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_lucky_pro_ic).toString(),
-    GameEntranceType.LUCKY_PRO
-)
-
-class TeenPattiEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_teen_patti_ic).toString(),
-    GameEntranceType.TEEN_PATTI
-)
-
-class RussianRouletteEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_russian_roulette_ic).toString(),
-    GameEntranceType.RUSSIAN_ROULETTE
-)
-
-class TexasCowboyEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_texas_cowboy_ic).toString(),
-    GameEntranceType.TEXAS_COWBOY
-)
-
-class DragonTigerEntrance : GameEntrance(
-    UriUtil.getUriForResourceId(com.adealink.weparty.R.drawable.common_dragon_tiger_ic).toString(),
-    GameEntranceType.DRAGON_TIGER_SLOT
-)
-
-data class RocketEntrance(var rocketLevel: Int, var progress: Int) : GameEntrance(
-    "",
-    GameEntranceType.ROCKET
-)

+ 1 - 1
module/room/src/main/java/com/adealink/weparty/room/gift/SendGiftFromChatDialog.kt

@@ -58,7 +58,7 @@ class SendGiftFromChatDialog : BottomDialogFragment(R.layout.dialog_send_gift_fr
     private val giftViewModel by fastLazy { GiftModule.getGiftViewModel(this@SendGiftFromChatDialog) }
 
     override val fgTag: String = TAG
-    override val canceledOnTouchOutside: Boolean = false
+    override var canceledOnTouchOutside: Boolean = false
 
     private var giftInfo: GiftInfo? = null
 

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů