Compare commits

...

582 Commits

Author SHA1 Message Date
renhaoting 479e8aad93 【埋点】Chest_Claim_Click(宝箱领取点击事件)在可以领取时就上报了,需要点击领取后上报。且事件中total_amount 属性上报错误,领取 0.1 奖励上报为 1 2026-01-23 18:12:22 +08:00
renhaoting 91260dc651 【埋点】福利任务完成事件应该是完成一个任务就上报一条,目前是全部完成了才会上报一条 2026-01-23 17:50:12 +08:00
renhaoting 38e13bf461 【埋点】adid 公共属性及用户属性目前上报为空 2026-01-23 15:23:25 +08:00
renhaoting ace9afbbbc 【埋点】adjust 初始化事件没有上报 (这个也需要检查在数数初始化之后再初始化 adjust 进行上报) 2026-01-23 15:01:05 +08:00
renhaoting 4eb4633d75 【埋点】Loading_Start 还是没有上报,麻烦检查下是否是先初始化数数再上报的事件,没有初始化事件无法上报 2026-01-23 11:11:41 +08:00
renhaoting ca586f4b3b 激励广告 修改3秒 2026-01-22 19:42:01 +08:00
renhaoting c6bbcfba64 en 多语言 2026-01-22 19:33:45 +08:00
renhaoting 3781711e2e 设置 position值 2026-01-22 19:30:29 +08:00
renhaoting 10b42951a8 position 值 修改。 2026-01-22 19:27:35 +08:00
renhaoting 2b3b5f905f 【adjust】游戏中已经提现了多次,adjust 中没有接收到事件上报 2026-01-22 18:35:42 +08:00
renhaoting e2371468b5 UI 居中 2026-01-22 17:44:48 +08:00
renhaoting af6e5e6ef1 【显示】填写cpf的弹框前面有个#号 2026-01-22 17:23:10 +08:00
renhaoting 1995e0b43f 【买量】游戏中没有区分买量和非买量的小额提现规则 2026-01-22 17:20:21 +08:00
renhaoting 68d4bc2948 firebase shushu 添加 super公用参数 2026-01-22 15:49:26 +08:00
renhaoting 7fff655e81 看 rv 增加的金币 times+1 2026-01-22 15:33:24 +08:00
renhaoting 02d6712928 增加 times 相关属性 2026-01-22 15:26:14 +08:00
renhaoting 5ebb3153b8 数数 公共super参数 2026-01-22 15:20:24 +08:00
renhaoting 0fc80a387e 【埋点】adjust 初始化时间每次都是 181 秒麻烦帮忙检查下 2026-01-22 14:16:09 +08:00
renhaoting c3a1455482 【埋点】推送界面展示事件中展示类型和展示位置上报为空 2026-01-22 13:55:23 +08:00
renhaoting 19f1dbe676 【埋点】H5 界面展示和点击事件都没有上报 2026-01-22 13:46:06 +08:00
renhaoting 5f7131e00c 【埋点】宝箱领取事件中领取总金额和可领取宝箱数属性上报为空 2026-01-22 11:57:04 +08:00
renhaoting 55c79e7d7e 【埋点】视频开始播放事件中上报了观看时长和是否完整播放的属性,这个时候刚开始观看不能上报 2026-01-22 11:01:16 +08:00
renhaoting 93f1cf9921 【异常】连续点击多次提现按钮会出现好几个CPF 界面重叠 2026-01-22 10:54:33 +08:00
renhaoting 4f7d2c495a 小额提现 看广告:未绑定银行逻辑 2026-01-22 10:35:43 +08:00
renhaoting b374519bb9 小额提现 看广告 2026-01-21 19:22:29 +08:00
renhaoting 26df5def50 【埋点】激励广告点击事件上报为RV_Button_Click_Game,需求中为RV_Button_Click和需求不符 2026-01-21 18:47:56 +08:00
renhaoting 44efca168c 0元购 赚钻石 position 2026-01-21 18:42:16 +08:00
renhaoting efb6eb02bc 新增 videoStream 上报类型 2026-01-21 18:29:32 +08:00
renhaoting 3745010e38 【埋点】广告点击事件和广告收益上报事件中 position 属性上报不一致 2026-01-21 18:10:02 +08:00
renhaoting 090e819e84 新建helper 类 2026-01-21 17:19:56 +08:00
renhaoting 1a9ea870e5 loading 启动时间 上报数值 2026-01-21 17:04:11 +08:00
renhaoting a2a458e6d9 【提现】目前提现公式中单个广告价值没有*5 导致看一个广告进度不会增加,麻烦确定下设定 2026-01-21 16:01:24 +08:00
renhaoting 439d04706b 【提现】0.1 档位只能提现一次,在成功提现之后 0.1 档位还可以重复提现 2026-01-21 15:34:56 +08:00
renhaoting 292c187a7a 【视频】视频已经成功播放,中间还显示转菊花效果 2026-01-21 15:17:41 +08:00
renhaoting b53faa22ec 测试: 添加禁用插屏广告 2026-01-21 15:05:02 +08:00
renhaoting 3fb4f3c4cc 【任务】在视频界面中观看激励视频任务进度没有增加 2026-01-21 14:53:04 +08:00
renhaoting 34d10148b2 归因信息 common user 设置到fb,shushu 2026-01-21 14:48:55 +08:00
renhaoting 1b80c05503 shushu加入 common 和 user param 2026-01-21 11:53:02 +08:00
renhaoting 7a7af80d31 firebase加入 common 和 user param 2026-01-21 11:44:08 +08:00
renhaoting 9be0e2246b 处理 01提现后没有隐藏UI item 2026-01-19 19:11:09 +08:00
renhaoting 396161e152 签到ad gold不显示问题 2026-01-19 18:53:32 +08:00
renhaoting 3c13586113 不设置为 refresh 2026-01-19 17:29:00 +08:00
renhaoting 51d3581513 更改日志位置 2026-01-19 17:06:41 +08:00
renhaoting 4f624189c8 SubWithdraw 提现中 pending 显示 2026-01-19 16:10:37 +08:00
renhaoting 096138fc89 0.1 正在提现那么 dim button
【提现】多次点击提现按钮如果提现失败会出现两个失败弹窗
2026-01-19 15:43:43 +08:00
renhaoting 1864a20dd2 concurrent 异常处理+1 2026-01-19 14:47:24 +08:00
renhaoting e5c70e3d25 concurrent 异常处理 2026-01-19 14:41:57 +08:00
renhaoting 0b91a47f05 【显示】提现弹框的关闭按钮建议可以再靠右一点 2026-01-19 14:18:11 +08:00
renhaoting 7d93fb2a3b 【优化】提现页面的CPF文本显示建议可以往左靠一点 2026-01-19 14:14:50 +08:00
renhaoting f587a99e71 提现添加1.0档位 2026-01-19 14:09:37 +08:00
renhaoting 560b680484 【提现】提现记录界面如附件所示的提示弹框可以再往右一点+1 2026-01-19 13:42:04 +08:00
renhaoting 4b4c2b8f07 【提现】提现记录界面如附件所示的提示弹框可以再往右一点 2026-01-19 13:39:55 +08:00
renhaoting d82655602e 【显示】填写cpf的弹框前面有个#号 2026-01-19 11:51:17 +08:00
renhaoting 9eed617b38 转为新的list 2026-01-19 10:46:35 +08:00
renhaoting 153f385503 【推送】连续点击推送信息会出现好几个界面叠加的情况 2026-01-16 18:37:24 +08:00
renhaoting e5797d5f80 【推送】播放广告时可以点击推送信息返回游戏界面中 2026-01-16 18:29:48 +08:00
renhaoting 60fa7faa2f 配置 处理 notify intent是否跳转 2026-01-16 17:59:25 +08:00
renhaoting afbc0cb815 【广告】开屏广告无法展示,直接进入了游戏 2026-01-16 17:11:56 +08:00
renhaoting d12cccb13c main 中尝试显示开屏广告 2026-01-16 17:04:07 +08:00
renhaoting c9e9984ee6 新增参数 needShowSplashAd 2026-01-16 16:53:17 +08:00
renhaoting 93ca811144 如果id为空,不参与竞价 2026-01-16 16:42:58 +08:00
renhaoting 732fa61869 【推送】用户解锁屏幕时没有出现推送信息 2026-01-16 16:01:31 +08:00
renhaoting 324d9fcdcf 【埋点】激励点位展示点位出现 position 字段上报为空的情况 2026-01-16 15:35:09 +08:00
renhaoting 14f6ddabb1 【埋点】广告收益没有上报 ad_impression 2026-01-16 14:45:18 +08:00
renhaoting 0233f4476f 移除无用文件 2026-01-16 11:46:23 +08:00
renhaoting 0262a19fba 【提现】点击激励按钮,广告结束之后,提现进度未变 2026-01-16 11:32:38 +08:00
renhaoting 20cf340eba 【签到】每日签到页面中,金币图标跟金币数量未对齐 2026-01-16 11:21:07 +08:00
renhaoting 3dcd943f5d 【签到】签到的底部按钮在检测到玩家已登录,则该按钮展示“Check-in Agora”(立即签到),实际显示为玩家未登录状态时的显示内容 2026-01-16 10:50:03 +08:00
renhaoting 44380be0f1 【新手任务】已完成的任务会消失,剩余未完成的任务会往上填充,实际游戏中已经完成的任务未消失 2026-01-15 19:25:40 +08:00
renhaoting 4e28a5e436 【签到】进行补签的时候,补签红框未移动至补签日期 2026-01-15 18:46:12 +08:00
renhaoting 309b2d1662 【提现】点击进入提现及记录界面,页面上方标题文本为大写,理应显示为首字母大写,其余字母小写 2026-01-15 18:25:38 +08:00
renhaoting 57ef04f86e 【推送】锁屏界面中推送信息显示不全 2026-01-15 18:11:28 +08:00
renhaoting aed14e7277 【多语言】CPF 输入框提示语言没有适配多语言 2026-01-15 16:40:49 +08:00
renhaoting 8822f94268 更改配置 2026-01-15 16:21:26 +08:00
renhaoting 7b86f83177 3秒钟 还未成功,就退出 不显示广告 2026-01-15 15:26:20 +08:00
renhaoting fa18c550ed homefrag flag 设置1 2026-01-15 14:31:34 +08:00
renhaoting 3ffa288046 homefrag flag 设置 2026-01-15 14:29:22 +08:00
renhaoting 0d5bbc5813 【多语言】弹出的看完广告提示没有适配葡萄牙语 2026-01-15 11:27:42 +08:00
renhaoting 028249864d 【视频】视频宝箱界面的奖励和实际加的奖励值不符合,显示为28,实际加了40 2026-01-15 11:12:58 +08:00
renhaoting c4924b8fa7 【提现】在提现过程中点击更改账号,如果不做任何改动,没办法点击继续按钮 2026-01-15 11:02:15 +08:00
renhaoting 84b7519992 每日签到按钮不可点击问题 2026-01-15 10:47:26 +08:00
renhaoting 5c1c6bd002 增加内存 2026-01-15 10:42:08 +08:00
renhaoting 4912fddee0 enable proguard 2026-01-14 15:21:10 +08:00
renhaoting c7482eda72 adjust 获取 gaid 2026-01-14 14:46:11 +08:00
renhaoting 466e83dadd 初始化回调测试 2026-01-14 11:35:07 +08:00
renhaoting f0e781def1 adjust 固定使用ENVIRONMENT_PRODUCTION 2026-01-14 11:07:06 +08:00
renhaoting 468f1255e4 新增日志 2026-01-14 11:03:14 +08:00
renhaoting 7847159a61 youtube player修改为使用本地lib 2026-01-14 10:44:13 +08:00
renhaoting a77f9709d8 新增 togglePlayingState2(isPlaying) 方法 2026-01-13 18:57:16 +08:00
renhaoting dae7ab4da9 随机生成巴西电话号码 2026-01-13 17:43:13 +08:00
renhaoting 49a96758aa 通知文案多语言 2026-01-13 17:36:42 +08:00
renhaoting f7df0fa888 去掉无用代码 2026-01-13 16:43:40 +08:00
renhaoting ee79f241e1 钻石测试 2026-01-13 16:20:05 +08:00
renhaoting edff0c408e 一些config 2026-01-13 16:14:22 +08:00
renhaoting 90620fbcaa bill混淆 keep 2026-01-13 15:06:21 +08:00
renhaoting 78c57b41ef 精简代码 2026-01-13 14:11:48 +08:00
renhaoting 577527472a 优化返回值 2026-01-13 13:45:03 +08:00
renhaoting 04b35f09a0 第一次 识别并保存 之前参加过的项目 2026-01-13 12:00:41 +08:00
renhaoting e28606c7d8 适配:join时 服务器返回obj 放置到了 currentList 2026-01-13 11:37:04 +08:00
renhaoting 922df7550e 文案 2026-01-13 10:39:34 +08:00
renhaoting ed5eec84af guide完成前 不打开通知 2026-01-12 20:15:40 +08:00
renhaoting 383b0a2be3 广告开关 2026-01-12 19:27:57 +08:00
renhaoting f56455c269 关闭广告 赋值 取值 2026-01-12 19:15:13 +08:00
renhaoting c277d73277 测试配置页面 2026-01-12 19:05:47 +08:00
renhaoting 2488046089 limit配置 2026-01-12 19:00:49 +08:00
renhaoting 774d4a4379 隐藏键盘 2026-01-12 18:38:38 +08:00
renhaoting 597b3935fa 居中 2026-01-12 18:31:40 +08:00
renhaoting 4d56fe2515 初始化名字 2026-01-12 18:16:58 +08:00
renhaoting 36e999a439 默认名字 2026-01-12 18:11:55 +08:00
renhaoting a9160244b3 名字修改 及保存 2026-01-12 18:08:46 +08:00
renhaoting 15512e8b30 我的 名字修改 2026-01-12 17:43:15 +08:00
renhaoting 53781eb544 增大签到点击区域 2026-01-12 17:07:39 +08:00
renhaoting 1d01835f48 背景区域还原 2026-01-12 16:40:02 +08:00
renhaoting 5e0cdb524c 每日签到点击区域 2026-01-12 16:37:20 +08:00
renhaoting a09bc4abf9 调整gold cash 点击区域 2026-01-12 16:32:35 +08:00
renhaoting 5753fccee5 设置背景 2026-01-12 16:26:13 +08:00
renhaoting 387d5d99b2 调整taskFrag UI 背景 2026-01-12 16:01:39 +08:00
renhaoting a651faf106 cash提示框大小调整 2026-01-12 15:51:47 +08:00
renhaoting ddbf7dd400 放大图标 2026-01-12 15:20:39 +08:00
renhaoting 0ffbda3334 直接翻页 也计数广告显示逻辑 2026-01-12 15:01:34 +08:00
renhaoting 5d49ce6a96 处理game center为 本地webview加载后再跳转 2026-01-12 14:31:17 +08:00
renhaoting 1e487a4f8d 去掉测试diamagnetic 2026-01-12 13:44:38 +08:00
renhaoting 6dcd2a93a2 金币转现金 提示toast 2026-01-12 13:37:53 +08:00
renhaoting 111e1a88b2 应用到 boxAct, 替换home drag 图标 2026-01-12 12:01:11 +08:00
renhaoting e7ab378394 领取成功显示 自定义toast 2026-01-12 11:30:12 +08:00
renhaoting ceb91122b0 自定义 view toast 2026-01-12 11:15:27 +08:00
renhaoting 89ced0be17 处理点击区域过小问题 2026-01-12 10:24:49 +08:00
renhaoting c55cf6baf0 刷视频 和 看完视频 都需要处理逻辑 2026-01-12 10:19:26 +08:00
renhaoting 54d943869f 暂时不截图 2026-01-10 16:18:47 +08:00
renhaoting d5e9bacab4 新增方法 2026-01-10 16:08:44 +08:00
renhaoting 0f8a41e1a1 确认一个视频观看完成逻辑 2026-01-10 13:42:02 +08:00
renhaoting 12b467d553 优化通知 Act 2026-01-09 19:14:30 +08:00
renhaoting eec7770215 普通签到后,金币奖励dialog 点击ad 继续跳转激励视频 2026-01-09 18:43:34 +08:00
renhaoting dc4ad47b9f 加上 debuggable 属性 2026-01-09 18:09:10 +08:00
renhaoting 4d80c09fb9 更换为传统banner key 2026-01-09 17:29:35 +08:00
renhaoting 7b24d8e3ff 编译成功配置 2026-01-09 17:09:03 +08:00
renhaoting 6d741d9ce5 保证能relase打包成功 2026-01-09 16:59:08 +08:00
renhaoting e051962bd8 优化依赖关系 2026-01-09 16:22:29 +08:00
renhaoting d770804d32 解决 VididinApp release编译错误 2026-01-09 15:30:39 +08:00
renhaoting 7f21fb10a5 200这个看上去没居中 2026-01-09 15:14:14 +08:00
renhaoting 2be4afaf07 debug时临时使用测试 ad——key 2026-01-09 15:02:49 +08:00
renhaoting 24f4b46b45 应用全部ad 相关key id+1 2026-01-09 14:38:19 +08:00
renhaoting 3fdb6a1a59 应用全部ad 相关key id 2026-01-09 14:17:43 +08:00
renhaoting ec8d7f9da0 通知cash、调整 2026-01-09 13:43:53 +08:00
renhaoting 255f5223e8 app 类调整 2026-01-09 13:33:37 +08:00
renhaoting 80b4e66aca Debug flag 2026-01-09 11:41:19 +08:00
renhaoting 91dfd9e5ae 添加混淆配置 2026-01-09 11:12:49 +08:00
renhaoting 9bed3e5467 稍微加深 颜色 2026-01-09 10:38:48 +08:00
renhaoting be09270891 播放界面调整 2026-01-08 19:28:15 +08:00
renhaoting 2a3c1cd35c Fix bug -
android:layout_marginHorizontal="12dp"
2026-01-08 18:44:00 +08:00
renhaoting b8bb2bbffe Fix bug - 新手引导改为 从哪一步退出,下次进游戏就从哪一步开始,如过引导在界面里,就等进入那个界面在弹出 2026-01-08 18:27:07 +08:00
renhaoting 241dda68c1 Fix bug - 第一次在任务界面点那个通知任务的按钮,正常弹出来“是否开启通知”了,但是点完允许之后,这个按钮没有置灰,还能点击,且每次点击都会出现视频的情况 2026-01-08 17:35:01 +08:00
renhaoting 30522430a9 Fix bug - 0.1前面加个R$,然后旁边的倒计时,字号可以稍微小一点 2026-01-08 17:15:33 +08:00
renhaoting bb00fb9dfb Fix bug - 推送的钱这里,需要判断一下,最多显示2位小数(不四舍五入) 2026-01-08 17:02:02 +08:00
renhaoting 670e1819f0 混淆 新增keep 2026-01-08 16:35:44 +08:00
renhaoting 446e882db2 临时替换youtubePlayer 为远程仓库拉取 2026-01-08 16:27:24 +08:00
renhaoting adf08dceb0 ktx runtime 统一使用tom 版本 2026-01-08 16:09:41 +08:00
renhaoting 2ae95eea06 调整 gson 版本 2026-01-08 15:50:27 +08:00
renhaoting bca9728977 修改通知字体颜色 2026-01-08 15:37:23 +08:00
renhaoting 9fa41f37cb 去掉权限提示框 2026-01-08 15:02:48 +08:00
renhaoting f69449e982 不显示 提示框 2026-01-08 14:57:10 +08:00
renhaoting 4d997c1c00 第一次提现奖励 2026-01-08 14:55:16 +08:00
renhaoting c1c8f25c65 小额提现记录 2026-01-08 14:48:58 +08:00
renhaoting 0b4e7b3ad3 新的广告相关id文件 2026-01-08 14:28:29 +08:00
renhaoting e4fd9f924a Float 修改为 double 2026-01-08 11:23:16 +08:00
renhaoting 37b6e641e3 Fix bug: - 提现文案 2026-01-08 11:20:22 +08:00
renhaoting c8f5ca7e97 Fix bug: - 任务界面的这几个活动的文案需要和之前一样一行显示 2026-01-08 10:47:21 +08:00
renhaoting 387adc3343 Fix bug: - 去掉多余跳转 2026-01-07 19:36:07 +08:00
renhaoting 9a7eb9f1ec Fix bug: - 文案需要居中显示,然后上下字的颜色看起来不一样? 2026-01-07 19:17:33 +08:00
renhaoting 55f7621eed Fix bug: - 后台配置的0元购好像卡不见了+1 2026-01-07 19:14:40 +08:00
renhaoting 99bafde438 Fix bug: - 后台配置的0元购好像卡不见了 2026-01-07 19:12:29 +08:00
renhaoting 5209af76ad Fix bug: - 大额提现的说明这里,文案可以帮忙调一下,把第4点挪到下一行显示 2026-01-07 19:03:11 +08:00
renhaoting 7d1e4b64b1 Fix bug: - 提现记录里失败的原因需要按照附件里那个多语言来 2026-01-07 18:57:27 +08:00
renhaoting d368441ddf Fix bug: - 调整新手礼物位置 2026-01-07 18:46:13 +08:00
renhaoting f41c3a0c63 Fix bug: - 我打开通知后,还会强行给我弹通知的那个弹窗 2026-01-07 18:39:10 +08:00
renhaoting 427b17bd85 Fix bug: - 宝箱任务 启动倒计时 从当日0点修改为当前 毫秒数 2026-01-07 18:37:40 +08:00
renhaoting 7a381c1ff6 Fix bug: - 文案需要居中显示,然后看视频得金币的那个200前面需要加个金币icon 2026-01-07 18:30:47 +08:00
renhaoting bb684928ca Fix bug: - 去掉Overlay 弹窗权限 2026-01-07 17:31:28 +08:00
renhaoting d60f608115 Fix bug: - 福利的另外两个宝箱的金额位置,前面也可以加上钞票图标,像第一个宝箱那种 2026-01-07 17:10:30 +08:00
renhaoting c641fa9931 Fix bug: - 红框部分文案需要去掉,红框底下的文案居中显示+1 2026-01-07 17:02:59 +08:00
renhaoting 7e6366ff78 Fix bug: - 红框部分文案需要去掉,红框底下的文案居中显示 2026-01-07 17:01:24 +08:00
renhaoting 5c142961f3 Fix bug: - 按钮好像被拉伸了,看上去有点怪,然后上面红框位置的金币icon可以大一点 2026-01-07 16:55:15 +08:00
renhaoting 53d1f25d0c Fix bug: - 去掉提现成功绿色背景+1 2026-01-07 16:51:59 +08:00
renhaoting b04725abf8 Fix bug: - 去掉提现成功绿色背景 2026-01-07 16:51:50 +08:00
renhaoting 1045282908 提现记录列表 2026-01-07 16:39:22 +08:00
renhaoting b02f07a3cc 去掉无用代码 2026-01-07 16:13:48 +08:00
renhaoting 24ab07d4b2 使用OpertionUUID,提到可能没有payoutId 2026-01-07 16:12:05 +08:00
renhaoting decd41b82d 保存提现init接口 itemId 2026-01-07 16:01:15 +08:00
renhaoting 2859edcc89 接收提现结果 - 显示dialog 2026-01-07 15:35:21 +08:00
renhaoting 82d7f7d9d8 统一处理提现流程逻辑+1 2026-01-07 15:30:26 +08:00
renhaoting e2bdd75db4 统一处理提现流程逻辑 2026-01-07 15:28:24 +08:00
renhaoting b73333f46f 合并提现记录到 unique RecordCash 2026-01-07 12:01:38 +08:00
renhaoting ecaa1ae372 Fix bug: 大额提现界面100%颜色改成绿色+1 2026-01-07 10:25:38 +08:00
renhaoting 0cba07f90a Fix bug: 大额提现界面100%颜色改成绿色 2026-01-06 19:49:26 +08:00
renhaoting 104cb4b36b Fix bug: 视频界面顶部有黑边+2 2026-01-06 19:38:34 +08:00
renhaoting 7ef097b157 Fix bug: 视频界面顶部有黑边+1 2026-01-06 19:32:50 +08:00
renhaoting a59dcba040 Fix bug: 视频界面顶部有黑边,然后右侧的下拉列表可以往下挪挪,有点高了,可以挪到我红圈的位置 2026-01-06 19:31:45 +08:00
renhaoting 0c8e6a2efe WithdrawItem 更改 2026-01-06 19:14:24 +08:00
renhaoting d47129dea7 根据产品要求提现新逻辑:一旦进入100% 条目,马上扣减现金+1 2026-01-06 17:59:47 +08:00
renhaoting ba220384cb 根据产品要求提现新逻辑:一旦进入100% 条目,马上扣减现金 2026-01-06 17:56:38 +08:00
renhaoting daa1d2b2ad 去掉多余负号 2026-01-06 17:14:08 +08:00
renhaoting 7950369c09 现金相关的全部修改为 double 2026-01-06 17:12:26 +08:00
renhaoting 4268521b7a Fix bug - 提现失败记录 2026-01-06 16:59:45 +08:00
renhaoting 64a093782e Fix bug - 去掉repeat 2026-01-06 16:44:44 +08:00
renhaoting c2191c5990 Fix bug - 统一开始提现方法 2026-01-06 16:35:03 +08:00
renhaoting 7bb5217fc8 Fix bug - 提现失败,统一文案 2026-01-06 16:25:13 +08:00
renhaoting 2a09e6f930 Fix bug - 加粗字体 2026-01-06 16:16:39 +08:00
renhaoting 105e2878b6 Fix bug - 1.中间这个图标已经重新切图了,可以换一下,不然下面的+200不太明显(+200也需要加粗显示)
2.上面的文字、中间的图、底下的按钮分的有点太开了,按照效果图的间隔调一下
2026-01-06 16:02:46 +08:00
renhaoting 61d5761ab0 Fix bug - 大额提现界面需要按照效果图改:
1.标题:
          2.绿色的背景不一样
          3.R$10需要加粗
          4.100%颜色改成绿色
          5.R$0.1加粗显示
          6.底下紫色提示框用错了
2026-01-06 15:52:29 +08:00
renhaoting 5a7e413d83 Fix bug - 大额提现可以做成上下能滚动的,不然那个字展示不完,会被按钮挡住 2026-01-06 15:33:20 +08:00
renhaoting 00910ad616 Fix bug - loading现在有10s,太慢了,需要优化一下,越快越好 2026-01-06 15:08:25 +08:00
renhaoting db0fdcc700 Fix bug - 提现引导的手指可以往右挪一点,让他指到按钮上 2026-01-06 14:57:11 +08:00
renhaoting ccd4d7750e Fix bug - 领取福利宝箱奖励后,那个置灰的领取按钮和领取前的绿色按钮大小需要一样长,不然有点奇怪 2026-01-06 14:51:53 +08:00
renhaoting 28eed14ab4 Fix bug - 第二个宝箱开启后,倒计时没有重置 2026-01-06 14:40:44 +08:00
renhaoting 2028831590 Fix bug - 提现记录界面的数字里,获得的数字前最好加上“+”,现在只有“-”,需要统一在前面加符号表达,会更清晰一点 2026-01-06 14:22:08 +08:00
renhaoting bcb11ef936 Fix bug - 历史记录 description 中%d 替换 2026-01-06 14:19:10 +08:00
renhaoting 4351f8f3c2 Fix bug - 提现记录界面的金币和discord图标对应错了,应该是右边附件里那两个 2026-01-06 14:11:53 +08:00
renhaoting fbfd00db69 Fix bug - 签到成功后,金币底下的数字不见了 2026-01-06 14:00:55 +08:00
renhaoting b7f82f247e Fix bug - 通知enable 金币需要自己主动领取 2026-01-06 13:49:40 +08:00
renhaoting 70da2d05a3 Fix bug - 手指下面压着的字也可以用遮罩挡住,像现在只露一点但没有完全露出来,会有点奇怪 2026-01-06 11:56:22 +08:00
renhaoting 72cbad2b2f Fix bug - 这两种置灰按钮颜色需要统一,俺下面的那种浅灰来 2026-01-06 11:47:08 +08:00
renhaoting 3da237172b Fix bug - 视频界面顶部有黑边,然后右侧的下拉列表可以往下挪挪,有点高了,可以挪到我红圈的位置 2026-01-06 11:37:14 +08:00
renhaoting 9281096819 Fix bug - 任务界面的这几个活动的文案需要和之前一样一行显示 2026-01-06 11:35:28 +08:00
renhaoting 8892f45258 Fix bug - 主界面的活动文案没有加进去 2026-01-06 11:21:09 +08:00
renhaoting f8c6101d07 Fix bug - 文案修改 2026-01-06 11:08:08 +08:00
renhaoting 24f2d63a4a FireBaseManager 调用 2026-01-06 10:36:29 +08:00
renhaoting cec3ba6ba8 去掉提现固定账号+1 2026-01-05 19:19:03 +08:00
renhaoting 85bceb3b68 去掉提现固定账号 2026-01-05 19:13:10 +08:00
renhaoting 54d878cd94 埋点shushu无数据问题处理 2026-01-05 18:56:28 +08:00
renhaoting 9fec4aeac6 埋点: g广告相关 2026-01-05 18:18:17 +08:00
renhaoting 81ad6111f4 埋点: adjust init 和 归因获取成功 2026-01-05 17:44:01 +08:00
renhaoting 10e988fd83 埋点: 推送相关 2026-01-05 17:33:01 +08:00
renhaoting 6fdceb52e2 埋点: Statisticutil 更改 别的modudle 2026-01-05 17:09:24 +08:00
renhaoting 074a3374df 埋点: 推送权限 2026-01-05 17:05:49 +08:00
renhaoting 3285bd7b06 埋点: init payout check 2026-01-05 16:52:20 +08:00
renhaoting f645aabc70 提现错误码 文案统一处理+1 2026-01-05 16:34:08 +08:00
renhaoting 0d092b8422 提现错误码 文案统一处理 2026-01-05 16:22:02 +08:00
renhaoting fa47bba027 埋点 - 提现 2026-01-05 15:26:00 +08:00
renhaoting 042fc1cb05 埋点 - game, 每日任务,抽奖等 2026-01-05 14:27:02 +08:00
renhaoting eceb294da1 埋点 - 宝箱福利 2026-01-05 14:06:52 +08:00
renhaoting d1bbf7c523 埋点 - video播放暂停+1 2026-01-05 13:37:14 +08:00
renhaoting af87e4da5d 埋点 - video播放暂停 2026-01-05 13:35:58 +08:00
renhaoting 6c858ca0d7 看激励广告 多种情况的埋点 2026-01-05 11:42:35 +08:00
renhaoting 6371d8075c guide 等 数据埋点 2026-01-04 19:11:05 +08:00
renhaoting b3a7a610a5 闪屏页 数据埋点 2026-01-04 18:56:41 +08:00
renhaoting 1123dc2c9e firebase 接入和部分方法 2026-01-04 18:18:31 +08:00
renhaoting a722d84f06 FireBaseManager 初步 2026-01-04 17:41:48 +08:00
renhaoting acac3099a6 上报多个方法定义 2026-01-04 17:07:41 +08:00
renhaoting ac91577c41 数数 appid 初始化 2026-01-04 16:43:30 +08:00
renhaoting 07bab8b94e topon 广告 上报延后(关闭时) 2026-01-04 16:04:35 +08:00
renhaoting 9ef0b062af 处理横屏ad后 dialog 不居中问题 2026-01-04 15:50:42 +08:00
renhaoting c5d7234d92 如果已经识别了用户是否买量,不在执行loop check 2026-01-04 15:36:28 +08:00
renhaoting 810a8e1329 上传广告收益 2026-01-04 15:27:50 +08:00
renhaoting 2e17e79616 adjust 判断是否是买量用户 2026-01-04 14:02:41 +08:00
renhaoting 85a247d6fd adjust 上传 2025-12-31 19:29:14 +08:00
renhaoting 1912a9f669 adjust 配置初步+1 2025-12-31 18:52:29 +08:00
renhaoting 53d1acedc9 adjust 配置初步 2025-12-31 18:48:19 +08:00
renhaoting 80038162cf 修改router 2025-12-31 18:22:40 +08:00
renhaoting 26892b1227 popmenu 和 notif 中game 使用新的 router 2025-12-31 18:11:18 +08:00
renhaoting d775268e11 去掉 shouldOverride 2025-12-31 17:54:59 +08:00
renhaoting e0938dac56 js 交互接口定义 2025-12-31 17:33:02 +08:00
renhaoting eb85079523 获取 gaid 2025-12-31 17:16:09 +08:00
renhaoting dc4871c8b0 webview 限制跳转到系统浏览器 2025-12-31 16:40:33 +08:00
renhaoting ac41cdf3f0 替换gamecenter url 2025-12-31 16:29:19 +08:00
renhaoting 9ef7ebe5c1 添加play 配置 2025-12-31 16:21:28 +08:00
renhaoting 9955d77a33 修改测试url 2025-12-31 15:31:18 +08:00
renhaoting 17f80a6539 新增game center act +1 2025-12-31 15:26:49 +08:00
renhaoting 9575b2a8f7 新增game center act 2025-12-31 15:22:28 +08:00
renhaoting 804df4e915 修改包名 2025-12-31 15:11:21 +08:00
renhaoting cf70646ef3 增加 importance 参数 2025-12-31 14:32:06 +08:00
renhaoting dc0c47659b 提高优先级 2025-12-31 14:16:51 +08:00
renhaoting b532d1daa8 更新常驻通知 金币,现金 宝箱等字符串 2025-12-31 13:57:33 +08:00
renhaoting 19f9895f23 常驻通知 数量赋值 2025-12-31 11:59:47 +08:00
renhaoting d4216c017c 常驻通知布局 icon替换 2025-12-31 11:44:20 +08:00
renhaoting 05a8460a05 常驻通知图标 2025-12-31 11:16:19 +08:00
renhaoting e14736ed01 notify 中 go 的 背景动画前期 2025-12-31 10:42:21 +08:00
renhaoting 0184772698 提现通知 UI 布局+1 2025-12-30 19:14:28 +08:00
renhaoting 705901d55c 提现通知 UI 布局 2025-12-30 19:09:10 +08:00
renhaoting 191d19a908 修改通知名称 2025-12-30 18:11:30 +08:00
renhaoting 37cbac1a2e 修改优先级 2025-12-30 17:53:53 +08:00
renhaoting 1489be0c64 system alert 权限 +1 2025-12-30 17:35:23 +08:00
renhaoting c050c4b6ba system alert 权限 2025-12-30 17:25:28 +08:00
renhaoting d632807122 添加时间间隔 限制 2025-12-30 16:44:02 +08:00
renhaoting efc140f512 不同类型触发机制, 从不同制定list随机选择 2025-12-30 16:24:49 +08:00
renhaoting 64ff009736 解锁屏幕显示通知 2025-12-30 15:56:33 +08:00
renhaoting 8a442dbd54 app安装,充电 通知 2025-12-30 15:36:09 +08:00
renhaoting 5630c02394 去掉测试代码 2025-12-30 14:43:14 +08:00
renhaoting 8f038ca3ea app 固定时间节点通知 2025-12-30 14:34:48 +08:00
renhaoting 5e5ba292bd app后台 提现通知 时间间隔 2025-12-29 18:15:02 +08:00
renhaoting c36b187f6b app后台 提现通知 2025-12-29 17:50:01 +08:00
renhaoting 6018362656 新的通知框架 2025-12-29 16:56:08 +08:00
renhaoting b59b858352 新增 handsUp通知 2025-12-29 15:29:11 +08:00
renhaoting 11a091a725 新增 NotitifyUtil 2025-12-29 14:32:07 +08:00
renhaoting 4c7c4fb56c bug修改 - 增加修改cash入口 2025-12-29 14:19:11 +08:00
renhaoting 7ef5257a16 bug修改 - 提现界面的进度值没有那么精确,举个例子:按理来说我1.10的钱,在10档位的进度值应该为10.1% 2025-12-29 13:58:27 +08:00
renhaoting 88c1520177 bug修改 - cash相关数值 Folat 修改 Double 2025-12-29 13:48:09 +08:00
renhaoting cd85982048 bug修改 - 不多次接受 结果 2025-12-29 11:43:28 +08:00
renhaoting b3fb4f0327 bug修改 - 任务界面的按钮置灰之后,还能点击跳转,预期是置灰的无法点击 2025-12-29 11:15:14 +08:00
renhaoting 20f17da637 bug修改 - 剩余天数问题 2025-12-26 19:17:27 +08:00
renhaoting 12aeabe6c4 bug修改 - 视频界面顶部有黑边,然后右侧的下拉列表可以往下挪挪,有点高了,可以挪到我红圈的位置 2025-12-26 19:01:01 +08:00
renhaoting ef2f079b2e bug修改 - 提现成功界面有点关不掉,要多点几次 2025-12-26 19:00:03 +08:00
renhaoting 96c3a11f1d bug修改 - 0.1档位提现成功后,需要隐藏该档位 2025-12-26 18:54:33 +08:00
renhaoting ee4616a245 bug修改 - 现在进入discord的判定条件是什么啊?我从任务界面进了discord,但是回到任务界面后,对应的任务奖励没有下发 2025-12-26 18:35:27 +08:00
renhaoting cff0703f24 bug修改 - 提现成功界面的标题和钱需要加粗,然后底下那一串文案说明需要居中,整个界面背后的光效呗拉伸了,和效果图不一样 2025-12-26 18:27:05 +08:00
renhaoting c7f430d58c bug修改 - 每刷3个视频不是会弹出激励广告嘛,激励广告弹出来如果点击关闭按钮,也需要加上插屏 2025-12-26 18:06:02 +08:00
renhaoting eb581c16ae bug修改 - 点击填账号那块,能看到里面是有账号的,但是外面没有显示,这个外面也需要显示的,想参考图那样 2025-12-26 17:58:54 +08:00
renhaoting 2527c6369f bug修改 - 显示银行账号 2025-12-26 17:49:39 +08:00
renhaoting 4960deb7c3 bug修改 - 跳转 观看视频60秒奖励40 2025-12-26 17:24:39 +08:00
renhaoting f5a9c11f62 bug修改 - 0元购guide调整 2025-12-26 17:13:15 +08:00
renhaoting 395ec8a371 bug修改 - 反向手指guide+1 2025-12-26 17:02:13 +08:00
renhaoting c6fe2c7c33 bug修改 - 反向手指guide 2025-12-26 16:48:37 +08:00
renhaoting 35c1119ddb bug修改 - 新手礼物 guide 优化 2025-12-26 16:28:27 +08:00
renhaoting bbee6dd808 bug修改 - menu 引导 按钮调整 2025-12-26 16:11:10 +08:00
renhaoting 8559ac16c1 bug修改 - 引导的手指需要加动画(顺着指的方向前后移动) 2025-12-26 15:42:25 +08:00
renhaoting 8a045117ea bug修改 - ui 对齐 2025-12-26 15:08:45 +08:00
renhaoting 5d217d025b bug修改 - 视频主界面的那个红包进度条,如果在进度条没有满的时候点击红包的话,可以加一个tips 2025-12-26 14:33:07 +08:00
renhaoting b010c1e4d2 bug修改 - 签到完成界面按钮上的文案需要加自适应,现在显示不完 2025-12-26 14:11:56 +08:00
renhaoting 1405041810 bug修改 - 签到获得奖励界面的顶部标题变成图片了 2025-12-26 13:57:56 +08:00
renhaoting a75d47a04c bug修改 - 签到界面可以优化一下, 改为点击当天的签到框,也能直接领取当天的签到奖励 2025-12-26 13:54:43 +08:00
renhaoting 63e867ad72 bug修改 - 提现界面总金额需要加粗显示,看着有点不太清楚 2025-12-26 13:49:12 +08:00
renhaoting 2d3326a00e bug修改 - 提现页提示文案 2025-12-26 13:48:24 +08:00
renhaoting 0f56ad235e 添加 0元购记录到cash记录, 文案添加 2025-12-26 13:37:27 +08:00
renhaoting 0f1a88e087 添加 0元购记录到 cash记录。
额外增加 总陈工提现数
2025-12-26 12:01:49 +08:00
renhaoting a5b4df0854 看激励视频dialog title 2025-12-26 11:39:20 +08:00
renhaoting 2cc2315306 签到title 替换 2025-12-26 11:34:41 +08:00
renhaoting 9dde21580f check 有结果时,发送事件通知,以便显示dialog 2025-12-26 11:18:43 +08:00
renhaoting ca097b392e 进入0元购时,检查未通知的 提现list,并通知 2025-12-26 11:14:02 +08:00
renhaoting 03aae381b2 轮询查询 0元购 提现结果 2025-12-25 19:35:34 +08:00
renhaoting 3fa2c5638f 数据线程安全locker 2025-12-25 18:51:56 +08:00
renhaoting ab540875e6 设置下划线 2025-12-25 18:47:03 +08:00
renhaoting 900f39e3bd winAct 的 adapter中实现 提现 2025-12-25 18:42:56 +08:00
renhaoting 08a81b1c7e 中奖记录页面,添加 领取奖励 click事件处理 2025-12-25 18:12:30 +08:00
renhaoting 6a8c0cc4df 提现dialog显示 步骤逻辑 2025-12-25 17:37:04 +08:00
renhaoting 8412415f86 布局优化 2025-12-25 17:13:17 +08:00
renhaoting 95cb9da2af 0元购 接入领取奖励 确认、绑定银行dialog 2025-12-25 16:53:59 +08:00
renhaoting 461a24de94 0元购manager 2025-12-25 16:24:33 +08:00
renhaoting 5c03d0cb06 修改bean,替换 0元购新接口 2025-12-25 14:08:27 +08:00
renhaoting adfa6bca79 颜色复制 2025-12-25 11:40:51 +08:00
renhaoting 727321ad70 record相关 图标 2025-12-25 11:31:16 +08:00
renhaoting 2001936032 record相关 文案加入 2025-12-25 11:04:25 +08:00
renhaoting c5c7ba71b7 新增ongoing类型 cash 记录 2025-12-25 10:42:51 +08:00
renhaoting 885bc67994 新增文案 2025-12-24 19:34:48 +08:00
renhaoting 7976c1f358 中奖 未中奖 dialog调整 赋值 2025-12-24 18:56:44 +08:00
renhaoting 84f367bdca 参与成功后再 扣减钻石 +1 2025-12-24 18:38:40 +08:00
renhaoting aefd72680b 参与成功后再 扣减钻石 2025-12-24 18:34:10 +08:00
renhaoting a3b0386c9d 去掉无用代码 2025-12-24 18:15:10 +08:00
renhaoting fc62d3a0cb loading 2025-12-24 17:51:03 +08:00
renhaoting 32553d70d1 金币记录 替换背景,赋值number 2025-12-24 17:27:31 +08:00
renhaoting 0e9eebd85a 金币记录 数据收集 2025-12-24 17:12:21 +08:00
renhaoting 4ab33f382c 现金记录数据 2025-12-24 16:31:38 +08:00
renhaoting 59c80a6e58 统一 金币 钻石 现金 存取方法 2025-12-24 16:04:05 +08:00
renhaoting 95da77184d 沉浸式 2025-12-24 15:20:37 +08:00
renhaoting 64556c9d7b 重构record bean对象,应用到 adapater+1 2025-12-24 15:17:58 +08:00
renhaoting 05f9af12de 重构record bean对象,应用到 adapater 2025-12-24 15:12:12 +08:00
renhaoting 3a3a7c10bd 三种记录manager 定义及存取方法 2025-12-24 14:30:15 +08:00
renhaoting 3b4e8522ec 解决 第一次就进入 通知 系统设置页面,而不是直接请求权限 2025-12-24 11:06:51 +08:00
renhaoting 8cbc29db36 tabs 居中显示 2025-12-23 19:36:49 +08:00
renhaoting 150c1a7107 隔3插屏广告 再隔5激励广告 2025-12-23 19:28:43 +08:00
renhaoting 64242f4905 去掉 anydpi icon 2025-12-23 18:47:28 +08:00
renhaoting 6ff7704cad 不直接配置const 的 appid 2025-12-23 18:10:51 +08:00
renhaoting f737254d0c 跳转隐私协议 2025-12-23 18:01:16 +08:00
renhaoting 183d31151b bug修复 - 文案未居中,discord点了没有跳转+1 2025-12-23 17:42:41 +08:00
renhaoting cacdbbbb9e bug修复 - 文案未居中,discord点了没有跳转 2025-12-23 17:39:48 +08:00
renhaoting 7e774a2733 bug修复 - discord链接好像放错了,点击之后跳到百度了 2025-12-23 17:37:23 +08:00
renhaoting 09b7eba3e7 bug修复 - 签到获得奖励界面的顶部标题变成图片了,然后+100要加粗 2025-12-23 17:30:02 +08:00
renhaoting cf5250d7ec bug修复 - 签到dialog 2025-12-23 17:28:05 +08:00
renhaoting 05721bcd46 bug修复 - 0元购没有钻石但还是可以参团+1 2025-12-23 17:09:57 +08:00
renhaoting 45c808618e bug修复 - 0元购没有钻石但还是可以参团 2025-12-23 17:08:13 +08:00
renhaoting c4b54f5e2e bug修复 - 加粗标题 2025-12-23 16:56:50 +08:00
renhaoting f2637531e4 bug修复 - 0元购的钻石广告,看一次广告应该只能获得1个钻石,现在是看一次能获得5个 2025-12-23 16:52:58 +08:00
renhaoting fe3f7e90ad bug修复 - 居中 2025-12-23 16:52:08 +08:00
renhaoting 9ba4eec4ed bug修复 - 宝箱剩余时间格式化 2025-12-23 16:47:00 +08:00
renhaoting a284e3cde5 bug修复 - 金币获取提醒 2025-12-23 16:30:59 +08:00
renhaoting e6cb9715d7 bug修复 - 金币获取提醒 2025-12-23 16:24:21 +08:00
renhaoting 837d4e8f5a bug修复 - 主界面的活动文案没有加进去+1 2025-12-23 16:06:35 +08:00
renhaoting 04e770da82 bug修复 - 主界面的活动文案没有加进去 2025-12-23 16:05:21 +08:00
renhaoting debb8acbcf bug修复 - 4个task tag信息 2025-12-23 15:35:44 +08:00
renhaoting e030324b5d bug修复 - 宝箱任务 图标问题 2025-12-23 15:25:12 +08:00
renhaoting 7b73b833c6 bug修复 - 根据产品修改 宝箱任务 重要逻辑 2025-12-23 15:05:43 +08:00
renhaoting 2c807ca4ee bug修复 - 宝箱领完之后,绿色底框上应该有“√”,现在没有 2025-12-23 11:58:09 +08:00
renhaoting f567e1bad9 bug修复 - 这段文案需要一行显示 2025-12-23 11:37:57 +08:00
renhaoting f78ae33ef3 bug修复-可领取但未领取的宝箱底下的绿色框里,字不见了,这里只剩底框从红变绿而已,里面的字还是需要保留的 2025-12-23 11:29:49 +08:00
renhaoting 03b5f0fba1 bug修复- 福利界面标题未居中,倒计时未加进去 2025-12-23 11:21:31 +08:00
renhaoting 64aa22a0de bug修复- 不主动收齐菜单 2025-12-22 19:34:11 +08:00
renhaoting 328cbd205d 弹出菜单迁移到 HomeFragment 2025-12-22 19:31:53 +08:00
renhaoting 02587b7e21 bug修复 - 签到完成界面按钮上的文案需要加自适应,现在显示不完 2025-12-22 18:44:27 +08:00
renhaoting 0a635e3b32 bug修复-签到界面直接点击领取双倍的按钮时,现在没有弹去看广告,是直接获得金币的 2025-12-22 18:39:52 +08:00
renhaoting f0cad1497f bug修复 2025-12-22 17:59:47 +08:00
renhaoting 37f73e12c5 提现item完成后,reset 重置逻辑 2025-12-22 17:34:13 +08:00
renhaoting 1aea476277 开启取现item任务后,事件通知及处理 2025-12-22 17:12:54 +08:00
renhaoting 38b8a8d23c 取现逻辑调整 2025-12-22 17:00:22 +08:00
renhaoting c2bb7ec0e7 bug修复 10 2025-12-22 14:51:32 +08:00
renhaoting 333e7616de bug修复7 2025-12-22 14:34:35 +08:00
renhaoting 189a85896a bug修复7 2025-12-22 14:32:16 +08:00
renhaoting 8c9dd06295 bug修复5, 6, 8 2025-12-22 14:13:34 +08:00
renhaoting 470c11d5b8 提现相关ui 2025-12-19 19:11:15 +08:00
renhaoting f54cb905f9 持久化通知+1 2025-12-19 16:08:50 +08:00
renhaoting d392527e4d 持久化通知 2025-12-19 15:46:56 +08:00
renhaoting 8d3b2a6d03 notification 初步 2025-12-19 11:08:08 +08:00
renhaoting 50341765a2 首页, 菜单 guide 2025-12-18 19:18:11 +08:00
renhaoting 9c83bbe0c1 新手dailog guide 2025-12-18 18:35:58 +08:00
renhaoting e996a48bec 签到 dialog 边距调整 2025-12-18 18:20:07 +08:00
renhaoting 8ec2821cc9 签到 dialog 9png 调整 2025-12-18 18:13:02 +08:00
renhaoting 3b657bef61 launcher icon 2025-12-18 17:59:30 +08:00
renhaoting 936176f400 去掉 带默认 app icon 的 window bg 2025-12-18 17:43:00 +08:00
renhaoting e325c00546 saplsh 界面 动画 2025-12-18 17:41:02 +08:00
renhaoting 92e073062e saplsh 界面 2025-12-18 17:25:37 +08:00
renhaoting 70cac6cd49 激励视频 提示 UI 2025-12-18 16:58:12 +08:00
renhaoting c90b15a7a2 解决 奖励奖励dialog 横屏后不居中问题 2025-12-18 16:49:53 +08:00
renhaoting d8b43d1082 WatchAdAct 背景透明 2025-12-18 16:46:35 +08:00
renhaoting f5a81c6b61 激励视频收益 传递 到 大额体现 2025-12-18 16:33:07 +08:00
renhaoting 2c0a52ec48 激励ad 关闭回调 2025-12-18 16:24:49 +08:00
renhaoting e251550ffb admob revence 回调 2025-12-18 15:51:15 +08:00
renhaoting afa8b2405c pangle回调返回 revence 2025-12-18 15:33:46 +08:00
renhaoting cef3efaa4e 激励广告 revence 值回调 2025-12-18 15:01:04 +08:00
renhaoting c981ffe950 激励视频广告 2025-12-18 13:36:59 +08:00
renhaoting 867c075794 打开 report 开机上报 2025-12-18 11:12:41 +08:00
renhaoting b5fc00b996 banner 基类统一设置 2025-12-18 10:41:11 +08:00
renhaoting ec9dabdc0e 统一设置 基类 2025-12-17 19:21:34 +08:00
renhaoting 1b38648b3a 统一到基类 2025-12-17 18:36:21 +08:00
renhaoting 08a09d8cf3 MainAct banner 广告 2025-12-17 16:15:18 +08:00
renhaoting 75a7355665 主界面 banner ad 2025-12-17 15:56:57 +08:00
renhaoting e36722ced8 视频页 插屏广告 2025-12-17 15:30:39 +08:00
renhaoting 3bebde7111 闪屏页添加广告 2025-12-17 14:35:21 +08:00
renhaoting 17441a0d78 新增splash页 2025-12-17 14:07:58 +08:00
renhaoting 96a3e641ce 新增bill模块 2025-12-17 13:41:41 +08:00
renhaoting ba4c5708db 领金币 转换现金 取现+1 2025-12-16 18:09:45 +08:00
renhaoting 02bc2837bd 领金币 转换现金 取现 2025-12-16 18:08:11 +08:00
renhaoting 8932c39064 新手任务 替换为 100金币 2025-12-16 17:38:44 +08:00
renhaoting 90dbd265f0 guide in 提现 和 0元购 2025-12-16 17:33:12 +08:00
renhaoting c1070ab095 guide 点击事件处理+1 2025-12-16 16:47:53 +08:00
renhaoting 21ace7f399 guide 点击事件处理 2025-12-16 16:46:43 +08:00
renhaoting 109b01d9c6 guide初步+1 2025-12-16 15:39:33 +08:00
renhaoting 994d205a7e guide初步 2025-12-16 15:26:22 +08:00
renhaoting e0ede99c67 更新接口 2025-12-15 17:38:15 +08:00
renhaoting 9059a5a415 扣减,回复 cash 2025-12-15 17:30:16 +08:00
renhaoting 5487b28be4 刷新UI 2025-12-15 17:14:20 +08:00
renhaoting 41f7f9a246 检查 提现进度 结果,ui更新+1 2025-12-15 17:04:26 +08:00
renhaoting b136df0f73 检查 提现进度 结果,ui更新 2025-12-15 16:42:35 +08:00
renhaoting 4e07aa4630 提现transaction check后各种事件通知以及接入处理 2025-12-15 16:17:25 +08:00
renhaoting c944b543b1 显示原来 账号 2025-12-15 14:07:14 +08:00
renhaoting 672f9cfb04 高阶回调 2025-12-15 14:03:21 +08:00
renhaoting a765fc7967 action 按钮 交互适配 2025-12-15 13:44:00 +08:00
renhaoting 53f75e0779 修改 selectingIndex 逻辑+1 2025-12-15 12:37:51 +08:00
renhaoting 1e73375a16 修改 selectingIndex 逻辑 2025-12-15 11:54:21 +08:00
renhaoting f889dc5072 添加subBean状态机 2025-12-15 11:39:03 +08:00
renhaoting 8f2786b5b9 进度事件通知及更新 2025-12-15 10:47:58 +08:00
renhaoting ae45b72717 广告完成后 事件通知逻辑优化 2025-12-12 18:41:05 +08:00
renhaoting 9066b775a8 调整传入参数 2025-12-12 17:23:21 +08:00
renhaoting 6cd007e6d4 跳转处理 2025-12-12 16:51:21 +08:00
renhaoting b9afc0fa14 提现root act UI调整2 2025-12-12 16:36:01 +08:00
renhaoting f8e8657159 提现root act UI调整1 2025-12-12 16:30:36 +08:00
renhaoting de9f32ae5b withdraw manager 以及ui赋值 2025-12-12 15:27:30 +08:00
renhaoting f8face95c6 大额提现子页面 rv 2025-12-12 13:54:09 +08:00
renhaoting f5ceeffaa8 跳转 及 调整ui 2025-12-11 19:07:48 +08:00
renhaoting 4a0a37e715 拆分 取现sub页面 title 2025-12-11 18:47:33 +08:00
renhaoting 968c5354a1 拆分 取现sub页面 2025-12-11 18:44:44 +08:00
renhaoting b09e9718a0 如果还有未知结果 交易,轮询check 2025-12-11 17:55:01 +08:00
renhaoting c0cd9cce33 调整逻辑+1 2025-12-11 17:39:45 +08:00
renhaoting da01786fd0 调整逻辑 2025-12-11 17:32:26 +08:00
renhaoting 5e86192b93 check 参数 2025-12-11 15:47:41 +08:00
renhaoting 3dfeaf54bf 提现 init 以及 payout 接口参数 适配 2025-12-11 15:24:31 +08:00
renhaoting 1a3b70076a 体现接口 调用 2025-12-10 19:21:11 +08:00
renhaoting 2ebaf58f56 看广告act 页面优化 2025-12-10 17:35:49 +08:00
renhaoting c9d281abcd 移包 2025-12-10 16:44:56 +08:00
renhaoting 32e4d6a6e7 定义请求方法 2025-12-10 16:43:16 +08:00
renhaoting cea438caa8 取现 http 接口定义 2025-12-10 16:30:44 +08:00
renhaoting c669384d3c 体现 resp req 对象 2025-12-10 16:00:31 +08:00
renhaoting c2b41a5309 右上角click问题 解决 2025-12-10 14:57:34 +08:00
renhaoting a237f7f5ac 中奖 未中奖dialog 赋值+1 2025-12-10 14:41:16 +08:00
renhaoting 2c791929ee 中奖 未中奖dialog 赋值 2025-12-10 14:40:48 +08:00
renhaoting 80812b5a2c 没有足够金钱提示 2025-12-10 13:39:29 +08:00
renhaoting 97344d2604 钻石事件 ui更新 2025-12-10 11:22:07 +08:00
renhaoting 595dfa7a9c 钻石 获取入口 2025-12-10 11:03:42 +08:00
renhaoting 8c48316daa 每日签到 9ppng 2025-12-10 10:39:45 +08:00
renhaoting 1a1edbb763 0元购记录+2 2025-12-09 19:07:46 +08:00
renhaoting b1dde3ef6c 0元购记录+1 2025-12-09 19:03:51 +08:00
renhaoting 6322e04a36 0元购记录 2025-12-09 18:59:40 +08:00
renhaoting 04c3223e5a 修改为 post 请求 2025-12-09 18:11:51 +08:00
renhaoting edc968f004 参加0元购 优化+1 2025-12-09 17:31:02 +08:00
renhaoting 542420b17a 参加0元购 优化 2025-12-09 17:23:02 +08:00
renhaoting a20e0053c1 银行账号验证 2025-12-09 17:07:11 +08:00
renhaoting 549817ef6e 调整签到提现布局 2025-12-09 16:56:06 +08:00
renhaoting 6925c42372 调整签到dialog布局 2025-12-09 16:32:38 +08:00
renhaoting 33e7503c70 还原设置 2025-12-09 16:13:42 +08:00
renhaoting 3b51532a34 修改包名+1 2025-12-09 15:28:54 +08:00
renhaoting ff2eab0da9 修改包名 2025-12-09 15:22:57 +08:00
renhaoting 0d31395d7a 解决crash 2025-12-09 14:39:35 +08:00
renhaoting 06fc43a454 排序 2025-12-09 14:20:09 +08:00
renhaoting a0ee013152 调整布局 滚动区域 2025-12-09 13:38:21 +08:00
renhaoting 66e47c4328 参加0元购逻辑 2025-12-09 11:53:33 +08:00
renhaoting 68f1119b4a Ui 调整赋值 2025-12-08 19:24:56 +08:00
renhaoting a95b8b84e9 调整布局 2025-12-08 18:54:26 +08:00
renhaoting 2dc819f916 元素adapter 2025-12-08 18:51:37 +08:00
renhaoting ce0d5084ba 保存userId 2025-12-08 18:26:52 +08:00
renhaoting 1988f2448c 接口接入 2025-12-08 18:12:28 +08:00
renhaoting 0f06e04a4e 一些基础util 2025-12-08 15:12:53 +08:00
renhaoting 3f10238136 ui美化+1 2025-12-05 19:25:12 +08:00
renhaoting b7ca0babe5 ui美化 2025-12-05 19:08:40 +08:00
renhaoting 47020ca736 去掉临时测试数据 2025-12-05 15:52:55 +08:00
renhaoting b143f6a67d 增加tab title 字体 2025-12-05 15:42:30 +08:00
renhaoting f934dd66ae item UI 美化+1 2025-12-05 15:36:49 +08:00
renhaoting 435faca163 item UI 美化 2025-12-05 15:31:45 +08:00
renhaoting 6dd6502c5a 记录UI 调整优化 2025-12-05 14:56:50 +08:00
renhaoting 09d74032a9 进度圈 2025-12-05 13:37:51 +08:00
renhaoting fedae8b98f 遮罩层 + 历史frag UI 2025-12-05 11:53:16 +08:00
renhaoting fb1c6011e0 去掉不必要ui 2025-12-04 18:16:10 +08:00
renhaoting f4b10782f0 key 和 proguadr 2025-12-04 17:50:51 +08:00
renhaoting b8d848e0bf 适配返回数据+1 2025-12-04 16:56:32 +08:00
renhaoting 2e2f37c586 适配返回数据 2025-12-04 16:44:30 +08:00
renhaoting dc65bd0562 请求接口更换-1 2025-12-04 16:29:15 +08:00
renhaoting 6831cfa898 层次调整 2025-12-04 15:42:14 +08:00
renhaoting 9bf2e8fef0 0元购 底部布局 2025-12-04 15:36:24 +08:00
renhaoting 4feda5f879 0元购 子view 2025-12-04 15:22:58 +08:00
renhaoting 4c4500b895 按钮置灰 2025-12-04 14:59:38 +08:00
renhaoting 81ab5823ec 新手任务状态 事件接入 updateUI 2025-12-04 14:56:33 +08:00
renhaoting 294100b146 新手任务状态UI 跟随更新 2025-12-04 14:34:02 +08:00
renhaoting 2b8b0fb38d 新手任务状态state类 2025-12-04 14:17:07 +08:00
renhaoting 9e2b880a32 媒体权限 2025-12-04 13:53:48 +08:00
renhaoting 57ae7ff4ff game跳转 2025-12-04 11:58:41 +08:00
renhaoting 95742607a0 跳转到三方二页面 2025-12-04 11:53:09 +08:00
renhaoting f2cbc14727 显示金币数量 2025-12-04 11:51:50 +08:00
renhaoting 47e4d3dba5 version act 赋值 2025-12-04 11:42:28 +08:00
renhaoting abe2f0ab90 隐私act 加载web 2025-12-04 11:30:37 +08:00
renhaoting 3b0abf5235 box 奖励获取 2025-12-04 11:27:27 +08:00
renhaoting 9189b845ef box跳转 / 事件 2025-12-04 11:02:00 +08:00
renhaoting 929a95ed9c 跳转到新手第一次体现 2025-12-04 10:39:31 +08:00
renhaoting 0991ab3993 首页展开 折叠优化 2025-12-03 19:30:11 +08:00
renhaoting 4ff522f3cd 签到事件发送 2025-12-03 19:11:10 +08:00
renhaoting a6c56d6539 完成UI 优化 2025-12-03 19:05:26 +08:00
renhaoting d7be7c30cb 4个类型的操作完成event 注册处理 2025-12-03 18:55:26 +08:00
renhaoting 66bcd4eb51 aciton but 跳转 2025-12-03 18:21:11 +08:00
renhaoting 114f7befbc 总进度及金额 读取 2025-12-03 17:54:48 +08:00
renhaoting 0bf9922be7 子任务根据state 刷新 2025-12-03 17:38:23 +08:00
renhaoting e6c0220019 当前box 子任务views 2025-12-03 17:09:05 +08:00
renhaoting ff0ee2d612 宝箱act 顶部UI刷新 +1 2025-12-03 16:55:30 +08:00
renhaoting 82ff8c5c51 宝箱act 顶部UI刷新 2025-12-03 16:39:52 +08:00
renhaoting 77d93b0211 sp宝箱statusbean 读取及初始化 2025-12-03 15:11:03 +08:00
renhaoting 3c081c230a UI调整 2025-12-03 14:30:42 +08:00
renhaoting e93d76f316 宝箱taskState 数据结构 2025-12-03 11:58:36 +08:00
renhaoting 483fa7e930 加入宝箱任务,并读取配置 2025-12-03 11:20:03 +08:00
renhaoting ca1f3662b0 日期变化监听 2025-12-03 10:48:32 +08:00
renhaoting 460270212d 当个观看广告奖励200 2025-12-02 18:42:05 +08:00
renhaoting ef8d084744 调整视频任务完成后 金币获取为主动获取 2025-12-02 17:56:44 +08:00
renhaoting 797d1c01a9 抽取 dailyTask 基类 2025-12-02 16:56:56 +08:00
renhaoting 554eaf31a3 跳转 2025-12-02 16:43:06 +08:00
renhaoting 9d8fc70c10 整理代码 2025-12-02 16:33:14 +08:00
renhaoting 16efb504e3 阶梯广告 UI 及时更新 2025-12-02 16:04:08 +08:00
renhaoting 62db69b1d4 更改事件 2025-12-02 15:23:39 +08:00
renhaoting 93543545c5 修改获取金币逻辑为 手动获取 2025-12-02 15:00:33 +08:00
renhaoting 32d201030d 观看ad UI监听及更新 2025-12-02 13:58:21 +08:00
renhaoting 6f650df200 观看ad 事件发送 2025-12-02 13:28:41 +08:00
renhaoting 0e034f340d 激励视频 UI显示更新 2025-12-02 11:44:48 +08:00
renhaoting b07c1cf4ab 光看广告task 2025-12-02 11:21:42 +08:00
renhaoting 0b0805d6bc 金币转现金 2025-12-01 19:26:14 +08:00
renhaoting da56a8cb42 调整广告页参数 2025-12-01 18:56:29 +08:00
renhaoting 97f9a39e95 初始时 读取 2025-12-01 18:21:29 +08:00
renhaoting a063466f15 保存最新每日watch状态 2025-12-01 18:09:19 +08:00
renhaoting dc7ff87e33 更新观看完成一个视频后更新 UI 2025-12-01 17:24:01 +08:00
renhaoting 63d636ff1a 每日观看 优化 2025-12-01 17:06:47 +08:00
renhaoting 1542db851e 从配置文件动态读取 每日观看个数阶梯任务 2025-12-01 16:13:44 +08:00
renhaoting f4aebf8e9c 每日观看个数 task bean 2025-12-01 15:38:11 +08:00
renhaoting 6ea2af01fe 新建其他bean 和 statusHelper 2025-12-01 15:11:53 +08:00
renhaoting 738b0b3ae9 优化taskmanager 结构+1 2025-12-01 14:46:11 +08:00
renhaoting 5fdf3a4ad9 优化taskmanager 结构 2025-12-01 12:00:18 +08:00
renhaoting e00bf1da76 计算已看视频个数 2025-11-28 19:06:09 +08:00
renhaoting f5162cb3a8 首页金币获取逻辑及UI 2025-11-28 18:07:11 +08:00
renhaoting df87261b62 读取新手任务金币数量到UI 2025-11-28 15:16:42 +08:00
renhaoting 58b33b9399 跳转discord 2025-11-28 14:54:51 +08:00
renhaoting 8b37a63a4a 打开系统通知设置 2025-11-28 14:47:21 +08:00
renhaoting cfe4acbb78 看广告act+1 2025-11-28 13:49:08 +08:00
renhaoting a8ab37a17b 看广告act 2025-11-28 11:25:45 +08:00
renhaoting 86214129b6 title 2025-11-28 11:16:10 +08:00
renhaoting fc7fd9d578 title 2025-11-28 11:14:21 +08:00
renhaoting b099f4cd99 dialog中使用mActivty 2025-11-28 11:06:25 +08:00
renhaoting 9efe53bf0d dialog中传递activity 2025-11-28 11:03:45 +08:00
renhaoting cb1e475a83 失败activity 2025-11-28 10:39:13 +08:00
renhaoting de9f003d26 提现成功 实现 2025-11-27 19:23:11 +08:00
renhaoting df332187d6 提现观看视频dialog-2 2025-11-27 19:01:39 +08:00
renhaoting 88c2d8cf34 提现观看视频dialog-1 2025-11-27 18:27:21 +08:00
renhaoting 3eb186063f 提现数值 传递 2025-11-27 18:11:10 +08:00
renhaoting 5a15d7d997 体现信息确认dialog UI 2025-11-27 17:59:52 +08:00
632 changed files with 49586 additions and 3739 deletions

1
.gitignore vendored
View File

@ -33,3 +33,4 @@ google-services.json
# Android Profiling # Android Profiling
*.hprof *.hprof
/.kotlin/sessions/kotlin-compiler-2258332710725417628.salive

1
StatisticReporter/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,67 @@
plugins {
alias(libs.plugins.androidLibrary)
alias(libs.plugins.kotlinAndroid)
id("com.google.firebase.crashlytics")
}
android {
namespace = "com.gamedog.statisticreporter"
compileSdk = 36
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.appcompat)
implementation(libs.material)
implementation(project(":base"))
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
implementation(project(":core:architecture"))
implementation(project(":bill"))
api("com.adjust.sdk:adjust-android:5.5.0")
api("com.android.installreferrer:installreferrer:2.2")
// Add the following if you are using the Adjust SDK inside web views on your app
api("com.adjust.sdk:adjust-android-webbridge:5.5.0")
api("com.android.installreferrer:installreferrer:2.2")
api("com.adjust.sdk:adjust-android-huawei-referrer:5.0.0")
api("com.google.android.gms:play-services-ads-identifier:18.2.0")
implementation("cn.thinkingdata.android:ThinkingAnalyticsSDK:3.0.2")
// 导入 Firebase BoMBill of Materials统一管理版本
implementation(platform("com.google.firebase:firebase-bom:33.16.0"))
// 添加你需要的 Firebase 产品依赖(无需指定版本号)
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-crashlytics")
implementation("com.google.firebase:firebase-config")
}

View File

120
StatisticReporter/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,120 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# ---------------------------------- 基础配置 ----------------------------------
# 代码优化次数通常设为5
-optimizationpasses 5
# 不使用混合大小写类名
-dontusemixedcaseclassnames
# 不忽略非公共库类
-dontskipnonpubliclibraryclasses
# 不进行预校验Android不需要可加快速度
-dontpreverify
# 打印混淆详情
-verbose
# 忽略警告
-ignorewarnings
# ---------------------------------- 保留重要属性 ----------------------------------
# 保留泛型签名重要避免JSON解析等类型转换错误
-keepattributes Signature
# 保留注解(如@Keep, @SerializedName等
-keepattributes *Annotation*
# 保留异常信息
-keepattributes Exceptions
# 保留源代码文件名和行号(便于崩溃日志分析)
-keepattributes SourceFile,LineNumberTable
# ---------------------------------- 保留Android基本组件 ----------------------------------
# 保留四大组件及其子类
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
# 保持 Native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保持 Parcelable 序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保持 Serializable 序列化的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保持自定义 View 的构造方法不被混淆(用于 XML 布局)
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
# 保持枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保持由 JSON 转换的 Bean 类(或者你的数据模型类)不被混淆
-keep class com.gamedog.vididin.beans.** { *; }
-keep class com.gamedog.vididin.router.** { *; }
# 保留R文件中的静态字段保证资源反射能正常工作
-keepclassmembers class **.R$* {
public static <fields>;
}
# gson
-keep class com.google.gson.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
# 明确保护被@SerializedName注解的字段
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
#okhttp
# OkHttp3
-dontwarn okhttp3.**
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okio.**
# Retrofit2
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature, Exceptions

View File

@ -0,0 +1,24 @@
package com.gamedog.statisticreporter
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.gamedog.statisticreporter.test", appContext.packageName)
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>

View File

@ -0,0 +1,159 @@
package com.gamedog.statisticreporter
import android.util.Log
import com.remax.bill.BuildConfig
/**
* 广告日志工具类
* 提供统一的日志输出控制和管理
*/
object StatisticLogger {
private const val TAG = "StatisticModule"
/**
* 日志开关默认为true
*/
private var isLogEnabled = BuildConfig.DEBUG
/**
* 设置日志开关
* @param enabled 是否启用日志
*/
fun setLogEnabled(enabled: Boolean) {
isLogEnabled = enabled
}
/**
* 获取日志开关状态
* @return 是否启用日志
*/
fun isLogEnabled(): Boolean = isLogEnabled
/**
* Debug日志
* @param message 日志消息
*/
fun d(message: String) {
if (isLogEnabled) {
Log.d(TAG, message)
}
}
/**
* Debug日志带参数
* @param message 日志消息模板
* @param args 参数列表
*/
fun d(message: String, vararg args: Any?) {
if (isLogEnabled) {
Log.d(TAG, message.format(*args))
}
}
/**
* Warning日志
* @param message 日志消息
*/
fun w(message: String) {
if (isLogEnabled) {
Log.w(TAG, message)
}
}
/**
* Warning日志带参数
* @param message 日志消息模板
* @param args 参数列表
*/
fun w(message: String, vararg args: Any?) {
if (isLogEnabled) {
Log.w(TAG, message.format(*args))
}
}
/**
* Error日志
* @param message 日志消息
*/
fun e(message: String) {
if (isLogEnabled) {
Log.e(TAG, message)
}
}
/**
* Error日志带异常
* @param message 日志消息
* @param throwable 异常对象
*/
fun e(message: String, throwable: Throwable?) {
if (isLogEnabled) {
Log.e(TAG, message, throwable)
}
}
/**
* Error日志带参数
* @param message 日志消息模板
* @param args 参数列表
*/
fun e(message: String, vararg args: Any?) {
if (isLogEnabled) {
Log.e(TAG, message.format(*args))
}
}
/**
* Error日志带参数和异常
* @param message 日志消息模板
* @param throwable 异常对象
* @param args 参数列表
*/
fun e(message: String, throwable: Throwable?, vararg args: Any?) {
if (isLogEnabled) {
Log.e(TAG, message.format(*args), throwable)
}
}
/**
* Info日志
* @param message 日志消息
*/
fun i(message: String) {
if (isLogEnabled) {
Log.i(TAG, message)
}
}
/**
* Info日志带参数
* @param message 日志消息模板
* @param args 参数列表
*/
fun i(message: String, vararg args: Any?) {
if (isLogEnabled) {
Log.i(TAG, message.format(*args))
}
}
/**
* Verbose日志
* @param message 日志消息
*/
fun v(message: String) {
if (isLogEnabled) {
Log.v(TAG, message)
}
}
/**
* Verbose日志带参数
* @param message 日志消息模板
* @param args 参数列表
*/
fun v(message: String, vararg args: Any?) {
if (isLogEnabled) {
Log.v(TAG, message.format(*args))
}
}
}

View File

@ -0,0 +1,122 @@
package com.gamedog.statisticreporter
import com.gamedog.statisticreporter.adjust.AdjustManager
import com.gamedog.statisticreporter.firbase.FireBaseManager
import com.gamedog.statisticreporter.shushu.ShushuManager
import com.remax.base.report.DataReportManager
import com.remax.base.report.DataReporter
import com.remax.bill.BuildConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
object StatisticUtil {
private lateinit var mGoldTimesFun: () -> Int
private lateinit var mCashTimesFun: () -> Int
private lateinit var mGoldFun: () -> Long
private lateinit var mCashFun: () -> Double
private val mBgScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
const val KEY_Loading_Start: String = "Loading_Start"
const val KEY_Loading_End: String = "Loading_End"
const val KEY_Home_Show: String = "Home_Show"
const val KEY_Guide: String = "Guide"
const val KEY_RV_Button_Show: String = "RV_Button_Show"
const val KEY_RV_Button_Click: String = "RV_Button_Click"
const val KEY_Video_Play_Start: String = "Video_Play_Start"
const val KEY_Video_Play_End: String = "Video_Play_End"
const val KEY_Welfare_Show: String = "Welfare_Show"
const val KEY_Chest_Claim_Click: String = "Chest_Claim_Click"
const val KEY_Welfare_Task_Click: String = "Welfare_Task_Click"
const val KEY_H5_Button_Click: String = "H5_Button_Click"
const val KEY_H5_Show: String = "H5_Show"
const val KEY_lottery_Button_Click: String = "lottery_Button_Click"
const val KEY_lottery_Show: String = "lottery_Show"
const val KEY_Daily_Task_Complete: String = "Daily_Task_Complete"
const val KEY_Daily_Sign: String = "Daily_Sign"
const val KEY_Withdraw_Click: String = "Withdraw_Click"
const val KEY_Withdrawal_Show: String = "Withdrawal_Show"
const val KEY_Withdrawal_finsh: String = "Withdrawal_finsh"
const val KEY_Withdrawal_Info: String = "Withdrawal_Info"
const val KEY_Withdrawal_Apply: String = "Withdrawal_Apply"
const val KEY_Withdrawal_Reason: String = "Withdrawal_Reason"
const val KEY_Push_Request_Show: String = "Push_Request_Show"
const val KEY_Push_Request_Result: String = "Push_Request_Result"
const val KEY_Push_Show: String = "Push_Show"
const val KEY_Push_Click: String = "Push_Click"
const val KEY_Push_EnterGame: String = "Push_EnterGame"
const val KEY_adjust_init: String = "adjust_init"
const val KEY_adjust_get_success: String = "adjust_get_success"
const val ad_click: String = "ad_click"
const val KEY_ad_close: String = "ad_close"
const val KEY_ad_start_load: String = "ad_start_load"
const val KEY_ad_loaded: String = "ad_loaded"
const val KEY_ad_load_fail: String = "ad_load_fail"
const val KEY_ad_show_fail: String = "ad_show_fail"
const val KEY_ad_position: String = "ad_position"
const val KEY_ad_impression: String = "ad_impression"
fun reportEvents(eventKey: String, eventData: Map<String, Any>? = null) {
mBgScope.launch {
val superPropertiesMap = mapOf("Money_Num" to mCashFun.invoke(),
"Coin_Num" to mGoldFun.invoke(),
"RV_Times_Coins" to mGoldTimesFun.invoke(),
"RV_Times_Money" to mCashTimesFun.invoke(),
"ad_network" to AdjustManager.instance().getNetwork(),
"adid" to AdjustManager.instance().getAaId()
)
FireBaseManager.instance().reportEvent(eventKey, eventData, superPropertiesMap)
ShushuManager.instance().reportEvent(eventKey, eventData, superPropertiesMap)
if (BuildConfig.DEBUG) {
StatisticLogger.d("Events reported to shushu&Firebase: type=$eventKey")
}
}
}
init {
initAdReporter()
}
private fun initAdReporter() {
DataReportManager.addReporters(object : DataReporter {
override fun getName(): String {
return "ThinkingData" //
}
override fun reportData(
eventName: String,
data: Map<String, Any>
) {
reportEvents(eventName, data)
}
override fun setCommonParams(params: Map<String, Any>) {
FireBaseManager.instance().setCommonParams(params)
ShushuManager.instance().setCommonParams(params)
}
override fun setUserParams(params: Map<String, Any>) {
FireBaseManager.instance().setUserParams(params)
ShushuManager.instance().setUserParams(params)
}
})
}
fun initCallbacks(cashCallback: ()->Double, goldCallback: ()->Long,
cashTimesCallback: ()->Int, goldTimesCallback: ()->Int) {
mCashFun = cashCallback
mGoldFun = goldCallback
mCashTimesFun = cashTimesCallback
mGoldTimesFun = goldTimesCallback
}
}

View File

@ -0,0 +1,364 @@
package com.gamedog.statisticreporter.adjust
import android.os.Handler
import android.os.HandlerThread
import android.text.TextUtils
import com.adjust.sdk.Adjust
import com.adjust.sdk.AdjustAdRevenue
import com.adjust.sdk.AdjustAttribution
import com.adjust.sdk.AdjustConfig
import com.adjust.sdk.AdjustEvent
import com.adjust.sdk.LogLevel
import com.adjust.sdk.OnAttributionChangedListener
import com.adjust.sdk.OnGoogleAdIdReadListener
import com.adjust.sdk.OnSessionTrackingFailedListener
import com.adjust.sdk.OnSessionTrackingSucceededListener
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DateUtil
import com.ama.core.architecture.util.SpUtil
import com.gamedog.statisticreporter.StatisticLogger
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.statisticreporter.adjust.AdjustManager.Companion.USER_TYPE_BUY
import com.remax.base.ads.AdRevenueData
import com.remax.base.ads.AdRevenueManager
import com.remax.base.ads.AdRevenueReporter
import com.remax.base.controller.UserChannelController
import com.remax.base.report.DataReportManager
import com.remax.bill.BuildConfig
class AdjustManager private constructor() {
companion object {
@Volatile
private var INSTANCE: AdjustManager? = null
fun instance(): AdjustManager {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: AdjustManager().also { INSTANCE = it }
}
}
const val ATTRI_TYPE_ORGANIC = "Organic"
const val ATTRI_TYPE_UNTRUSTED = "Untrusted Devices"
const val ATTRI_TYPE_GOOGLE = "Google Organic Search"
const val USER_TYPE_NORMAL = 1
const val USER_TYPE_BUY = 2
}
private var mGaid: String = ""
private var mAdid: String = ""
private var mAttribution: AdjustAttribution? = null
private var initStartTime: Long = 0
private var mAdjustInitStartMs: Long = 0
private val mAppContext = BaseApp.appContext()
private val mSpHelper = SpHelper()
private val mUserFromCheckRunnable = kotlinx.coroutines.Runnable {
run {
// 所有用户一开始都是自然用户的状态需要通过调用setOnAttributionChangedListener这个方法这个方法就是返回用户改变后的状态获得买量来源信息
Adjust.getAttribution { attribution ->
mAttribution = attribution
val networkFrom = attribution.network
var userTypeInt = 0
if (!TextUtils.isEmpty(networkFrom)) {
if (networkFrom.contains(ATTRI_TYPE_GOOGLE) || networkFrom.contains(ATTRI_TYPE_UNTRUSTED)) {
userTypeInt = USER_TYPE_NORMAL
} else if (!networkFrom.contains(ATTRI_TYPE_ORGANIC)) {
userTypeInt = USER_TYPE_BUY
}
}
if (userTypeInt > 0) {
saveUserType(userTypeInt)
mChecker.stopPolling()
}
}
}
}
private fun saveUserType(userType: Int) {
mSpHelper.saveUserType(userType)
}
private val mChecker: PollCheckHelper = PollCheckHelper(180,
3, mUserFromCheckRunnable, {
saveUserType(USER_TYPE_NORMAL)
})
fun initSdk(appToken: String) {
initStartTime = DateUtil.getCurTimeMs()
CommonParamsManager.initLoginParams()
StatisticLogger.d("登录参数初始化完成 - login_day: ${CommonParamsManager.loginDay ?: ""}, is_new: ${CommonParamsManager.isNew ?: ""}")
/// 先设置登录参数到DataReportManager
val loginParams = CommonParamsManager.getAllCommonParams()
val userParams = CommonParamsManager.getUserCommonParams()
DataReportManager.setCommonParams(loginParams)
DataReportManager.setUserParams(userParams)
StatisticLogger.d("登录参数已设置到DataReportManager: $loginParams")
// 初始化埋点
DataReportManager.reportData("adjust_init", mapOf())
val isDebug = BuildConfig.DEBUG
val environment = if (/*isDebug*/false) AdjustConfig.ENVIRONMENT_SANDBOX else AdjustConfig.ENVIRONMENT_PRODUCTION
val config = AdjustConfig(mAppContext, appToken, environment).apply {
setLogLevel(if (isDebug) LogLevel.VERBOSE else LogLevel.WARN)
enableSendingInBackground()
enableCostDataInAttribution()
/*enableCoppaCompliance()
enableCostDataInAttribution()*/
onSessionTrackingFailedListener = OnSessionTrackingFailedListener { failSession ->
}
onSessionTrackingSucceededListener = OnSessionTrackingSucceededListener {
val test = 111
}
onAttributionChangedListener = OnAttributionChangedListener { attribution->
handleAttribution(attribution)
}
}
StatisticUtil.reportEvents(StatisticUtil.KEY_adjust_init)
mAdjustInitStartMs = System.currentTimeMillis()
Adjust.initSdk(config)
Adjust.enable()
Adjust.getGoogleAdId(BaseApp.appContext(), OnGoogleAdIdReadListener { gaId->
mGaid = gaId
})
Adjust.getAdid { adId->
mAdid = adId
}
if (!mSpHelper.hasIdentityUserType()) {
mChecker.startPolling()
} else {
Adjust.getAttribution {
handleAttribution(it)
}
}
AdRevenueManager.addReporter(object: AdRevenueReporter {
override fun reportAdRevenue(adRevenueData: AdRevenueData) {
reportAdRevenueInfo(adRevenueData)
}
} )
}
private fun handleAttribution(attr: AdjustAttribution) {
mAttribution = attr
// 设置公共参数,并限制长度
CommonParamsManager.adNetwork = (attr.network ?: "").take(10)
CommonParamsManager.campaign = (attr.campaign ?: "").take(20)
CommonParamsManager.adgroup = (attr.adgroup ?: "").take(10)
CommonParamsManager.creative = (attr.creative ?: "").take(20)
StatisticLogger.d("公共参数设置完成 - ad_network: ${CommonParamsManager.adNetwork}, campaign: ${CommonParamsManager.campaign}, adgroup: ${CommonParamsManager.adgroup}, creative: ${CommonParamsManager.creative}")
// 将公共参数设置到DataReportManager
val commonParams = CommonParamsManager.getAllCommonParams()
val userParams = CommonParamsManager.getUserCommonParams()
DataReportManager.setCommonParams(commonParams)
DataReportManager.setUserParams(userParams)
StatisticLogger.d("公共参数已设置到DataReportManager: $commonParams")
// 计算从初始化开始到归因回调的总耗时(秒数,向上取整)
val totalDurationSeconds = kotlin.math.ceil((System.currentTimeMillis() - initStartTime) / 1000.0).toInt()
StatisticLogger.d("Adjust初始化到归因回调总耗时: ${totalDurationSeconds}")
DataReportManager.reportData(StatisticUtil.KEY_adjust_get_success, mapOf("pass_time" to totalDurationSeconds))
// 设置当前用户渠道类型
val userChannelType = if (StatisticLogger.isLogEnabled()) {
// 内部版本强制设置为买量类型
StatisticLogger.d("内部版本强制设置为买量类型")
UserChannelController.UserChannelType.PAID
} else {
determineUserChannelType(attr)
}
StatisticLogger.d("根据归因数据判断用户渠道类型: $userChannelType")
// 设置用户渠道类型
val success = UserChannelController.setChannel(userChannelType)
if (success) {
StatisticLogger.i("用户渠道类型设置成功: $userChannelType")
} else {
StatisticLogger.w("用户渠道类型已经设置过,无法修改")
}
}
private fun determineUserChannelType(attribution: AdjustAttribution): UserChannelController.UserChannelType {
// 获取归因数据的关键字段
val network = attribution.network?.lowercase()
val trackerName = attribution.trackerName?.lowercase()
val campaign = attribution.campaign?.lowercase()
StatisticLogger.d("归因数据 - network: $network, trackerName: $trackerName, campaign: $campaign")
// 判断是否为自然渠道的条件
val isOrganic = when {
// 1. Organic - 有机渠道
network == "organic" -> {
StatisticLogger.d("检测到Organic渠道")
true
}
// 2. Untrusted Devices - 不可信设备
network == "untrusted devices" -> {
StatisticLogger.d("检测到Untrusted Devices渠道")
true
}
// 3. Google Organic Search - Google有机搜索
network == "google organic search" -> {
StatisticLogger.d("检测到Google Organic Search渠道")
true
}
// 4. 其他情况都认为是买量渠道
else -> {
StatisticLogger.d("检测到买量渠道 - network: $network")
false
}
}
return if (isOrganic) {
UserChannelController.UserChannelType.NATURAL
} else {
UserChannelController.UserChannelType.PAID
}
}
private fun reportAdRevenueInfo(revenueValue: AdRevenueData) {
val adjustAdRevenue = AdjustAdRevenue(getRandomFixSourceStr()).apply {
setRevenue(revenueValue.revenue.value, revenueValue.revenue.currencyCode /*"USD"*/) // ad收益数值及单位
setAdRevenueNetwork(revenueValue.adRevenueNetwork) // 渠道来源
setAdRevenueUnit(revenueValue.adRevenueUnit) // ad收入来源单元
setAdRevenuePlacement(revenueValue.adRevenuePlacement) // 位置
}
Adjust.trackAdRevenue(adjustAdRevenue)
}
/**
* val event = AdjustEvent("g3mfiw")
* event.setCallbackId("f2e728d8-271b-49ab-80ea-27830a215147")
*/
fun reportAdjustEvent(event: AdjustEvent, callbackId: String?) {
callbackId?.let {
event.callbackId = callbackId
}
Adjust.trackEvent(event)
}
fun isUserBuy(): Boolean {
return mSpHelper.isUserBuy()
}
//----------------------- PRIVATE ------------------------//
private fun getRandomFixSourceStr(): String {
val randomInt = AndroidUtil.randomInt(1, 10)
return if (randomInt <= 2) "ironsource_sdk" else "applovin_max_sdk"
}
fun getNetwork(): String {
return mAttribution?.network ?: ""
}
fun getGaId(): String {
return mGaid
}
fun getAaId(): String {
return mAdid
}
}
class SpHelper {
companion object {
const val KEY_USER_FROM_TYPE = "KEY_USER_FROM_TYPE" // 1:自然用户 2买量用户
}
private var mUserType = SpUtil.instance().getInt(KEY_USER_FROM_TYPE)
fun hasIdentityUserType(): Boolean {
return mUserType > 0
}
fun saveUserType(userType: Int) {
mUserType = userType
SpUtil.instance().putInt(KEY_USER_FROM_TYPE, mUserType)
}
fun isUserBuy(): Boolean {
return mUserType == USER_TYPE_BUY
}
}
class PollCheckHelper(private val mTotalCheckSec: Int,
private val mTotalCheckGapSec: Int,
private val mCheckRunnable: Runnable,
private val mFinishCallback: ()->Unit) {
private var handlerThread: HandlerThread? = null
private var handler: Handler? = null
private var mStartMs: Long = 0L
private var mPollRunnable: Runnable? = null
private var mHasStop = false
private var mHasStarted = false
fun startPolling() {
if (mHasStarted) {
return
}
handlerThread = HandlerThread("PollingThread").apply { start() }
handler = Handler(handlerThread!!.looper)
mStartMs = System.currentTimeMillis()
mPollRunnable = Runnable {
mCheckRunnable.run()
val hasExpired = System.currentTimeMillis() - mStartMs >= mTotalCheckSec * 1000
if (hasExpired || mHasStop) {
stopPolling()
if (hasExpired) {
mFinishCallback.invoke()
}
} else {
handler?.postDelayed(mPollRunnable!!, mTotalCheckGapSec * 1000L)
}
}
handler?.post(mPollRunnable!!)
mHasStarted = true
}
fun stopPolling() {
mHasStop = true
mPollRunnable?.let {
handler?.removeCallbacks(it)
}
handlerThread?.quitSafely()
mPollRunnable = null
}
}

View File

@ -0,0 +1,145 @@
package com.gamedog.statisticreporter.adjust
import com.remax.base.ext.KvStringDelegate
import java.util.Calendar
import java.util.Locale
/**
* 公共参数管理器
* 管理数据上报的公共参数使用KvStringDelegate持久化
*/
object CommonParamsManager {
private const val KEY_AD_NETWORK = "common_param_ad_network"
private const val KEY_CAMPAIGN = "common_param_campaign"
private const val KEY_ADGROUP = "common_param_adgroup"
private const val KEY_CREATIVE = "common_param_creative"
private const val KEY_LOGIN_DAY = "common_param_login_day"
private const val KEY_IS_NEW = "common_param_is_new"
private const val KEY_FIRST_INSTALL_DATE = "first_install_date"
// 使用KvStringDelegate进行持久化存储默认值为空字符串
var adNetwork by KvStringDelegate(KEY_AD_NETWORK, "")
var campaign by KvStringDelegate(KEY_CAMPAIGN, "")
var adgroup by KvStringDelegate(KEY_ADGROUP, "")
var creative by KvStringDelegate(KEY_CREATIVE, "")
var loginDay by KvStringDelegate(KEY_LOGIN_DAY, "")
var isNew by KvStringDelegate(KEY_IS_NEW, "")
private var firstInstallDate by KvStringDelegate(KEY_FIRST_INSTALL_DATE, "")
/**
* 初始化登录相关参数
* 在应用启动时调用自动计算login_day和is_new
*/
fun initLoginParams() {
val currentDate = getCurrentDateString()
val storedFirstInstallDate = firstInstallDate ?: ""
if (storedFirstInstallDate.isEmpty()) {
// 首次安装,记录安装日期
firstInstallDate = currentDate
loginDay = "0"
isNew = "Y"
} else {
// 非首次安装,计算登录天数
val daysDiff = calculateDaysDifference(storedFirstInstallDate, currentDate)
loginDay = daysDiff.toString()
isNew = if (daysDiff == 0) "Y" else "N"
}
}
/**
* 获取当前日期字符串格式yyyy-MM-dd
* @return 当前日期字符串
*/
private fun getCurrentDateString(): String {
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH) + 1
val day = calendar.get(Calendar.DAY_OF_MONTH)
return String.format(Locale.ENGLISH, "%04d-%02d-%02d", year, month, day)
}
/**
* 计算两个日期之间的天数差
* @param startDate 开始日期格式yyyy-MM-dd
* @param endDate 结束日期格式yyyy-MM-dd
* @return 天数差
*/
private fun calculateDaysDifference(startDate: String, endDate: String): Int {
return try {
val startCalendar = parseDateToCalendar(startDate)
val endCalendar = parseDateToCalendar(endDate)
if (startCalendar == null || endCalendar == null) {
return 0
}
// 重置时间部分,只比较日期
startCalendar.set(Calendar.HOUR_OF_DAY, 0)
startCalendar.set(Calendar.MINUTE, 0)
startCalendar.set(Calendar.SECOND, 0)
startCalendar.set(Calendar.MILLISECOND, 0)
endCalendar.set(Calendar.HOUR_OF_DAY, 0)
endCalendar.set(Calendar.MINUTE, 0)
endCalendar.set(Calendar.SECOND, 0)
endCalendar.set(Calendar.MILLISECOND, 0)
// 计算天数差
val diffInMillis = endCalendar.timeInMillis - startCalendar.timeInMillis
(diffInMillis / (24 * 60 * 60 * 1000)).toInt()
} catch (e: Exception) {
0
}
}
/**
* 将日期字符串解析为Calendar对象
* @param dateString 日期字符串格式yyyy-MM-dd
* @return Calendar对象解析失败返回null
*/
private fun parseDateToCalendar(dateString: String): Calendar? {
return try {
val parts = dateString.split("-")
if (parts.size != 3) return null
val year = parts[0].toInt()
val month = parts[1].toInt() - 1 // Calendar的月份从0开始
val day = parts[2].toInt()
val calendar = Calendar.getInstance()
calendar.set(year, month, day)
calendar
} catch (e: Exception) {
null
}
}
/**
* 获取所有公共参数
* @return 公共参数Map
*/
fun getAllCommonParams(): Map<String, String> {
return mapOf(
"ad_network" to (adNetwork ?: ""),
"campaign" to (campaign ?: ""),
"adgroup" to (adgroup ?: ""),
"creative" to (creative ?: ""),
"login_day" to (loginDay ?: ""),
"is_new" to (isNew ?: "")
)
}
fun getUserCommonParams(): Map<String, String> {
return mapOf(
"user_ad_network" to (adNetwork ?: ""),
"user_campaign" to (campaign ?: ""),
"user_adgroup" to (adgroup ?: ""),
"user_creative" to (creative ?: ""),
"user_login_day" to (loginDay ?: ""),
"user_is_new" to (isNew ?: "")
)
}
}

View File

@ -0,0 +1,313 @@
package com.gamedog.statisticreporter.firbase
import android.R.string
import android.content.Context
import android.os.Bundle
import cn.thinkingdata.analytics.TDAnalytics
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.util.AndroidUtil.Companion.gson
import com.gamedog.statisticreporter.StatisticLogger
import com.google.firebase.Firebase
import com.google.firebase.FirebaseApp
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import java.util.concurrent.ConcurrentHashMap
class FireBaseManager private constructor() {
companion object {
@Volatile
private var INSTANCE: FireBaseManager? = null
fun instance(): FireBaseManager {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: FireBaseManager().also { INSTANCE = it }
}
}
}
private val mAppContext = BaseApp.appContext()
private val mBgScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val mMainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private lateinit var mFbAnalytics: FirebaseAnalytics
private val mDefaultParams = ConcurrentHashMap<String, Any>()
init {
FirebaseApp.initializeApp(mAppContext)
if (!::mFbAnalytics.isInitialized) {
mFbAnalytics = Firebase.analytics// FirebaseAnalytics.getInstance(mAppContext)
}
}
fun reportEvent(
eventName: String,
parameters: Map<String, Any>? = null,
superPropertiesMap: Map<String, Any>
) {
if (!::mFbAnalytics.isInitialized) {
throw IllegalStateException("FirebaseAnalyticsUtil not initialized. Call init() first.")
}
val bundle = Bundle().apply {
// 默认参数添加
mDefaultParams.forEach { (key, value) ->
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Boolean -> putBoolean(key, value)
}
}
superPropertiesMap.forEach { (key, value) ->
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Boolean -> putBoolean(key, value)
}
}
// 本次事件特定参数添加
parameters?.forEach { (key, value) ->
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Boolean -> putBoolean(key, value)
else -> putString(key, value.toString())
}
}
}
mFbAnalytics.logEvent(eventName, bundle)
}
fun getSSSuperProperties(): String{
val superPros = TDAnalytics.getSuperProperties()
return superPros.toString()
}
fun getDistinctId(): String{
return TDAnalytics.getDistinctId()
}
/**
* 记录推荐事件使用 Firebase 预设事件类型
* @param eventType 事件类型 FirebaseAnalytics.Event.SELECT_CONTENT
* @param parameters 事件参数
*/
fun reportRecommendedEvent(eventType: String, parameters: Bundle) {
if (!::mFbAnalytics.isInitialized) {
throw IllegalStateException("FirebaseAnalyticsUtil not initialized. Call init() first.")
}
mFbAnalytics.logEvent(eventType, parameters)
}
/**
* 设置用户属性
* @param propertyName 属性名称
* @param propertyValue 属性值
*/
fun setUserProperty(propertyName: String, propertyValue: String) {
if (!::mFbAnalytics.isInitialized) return
mFbAnalytics.setUserProperty(propertyName, propertyValue)
}
/**
* 设置用户ID
* @param userId 用户唯一标识
*/
fun setUserId(userId: String) {
if (!::mFbAnalytics.isInitialized) return
mFbAnalytics.setUserId(userId)
}
/**
* 设置当前屏幕
* @param screenName 屏幕名称
* @param screenClass 屏幕类名可选
*/
fun setCurrentScreen(context: Context, screenName: String, screenClass: String? = null) {
if (!::mFbAnalytics.isInitialized) return
val bundle = Bundle().apply {
putString(FirebaseAnalytics.Param.SCREEN_NAME, screenName)
screenClass?.let { putString(FirebaseAnalytics.Param.SCREEN_CLASS, it) }
}
mFbAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle)
}
/**
* 设置默认事件参数将自动添加到每个事件中
* @param parameters 默认参数映射
*/
fun setDefaultEventParameters(parameters: Map<String, Any>) {
mDefaultParams.clear()
mDefaultParams.putAll(parameters)
}
/**
* 添加单个默认事件参数
*/
fun addDefaultEventParameter(key: String, value: Any) {
mDefaultParams[key] = value
}
/**
* 清除所有默认事件参数
*/
fun clearDefaultEventParameters() {
mDefaultParams.clear()
}
fun setUserParams(params: Map<String, Any>) {
try {
// 如果获取为空,则异步等待阻塞获取
/*if (analytics == null) {
StatisticLogger.d("Firebase Analytics未就绪开始异步等待...")
analytics = runBlocking {
waitForFirebaseAnalytics()
}
}*/
if (mFbAnalytics == null) {
StatisticLogger.w("无法获取Firebase Analytics实例跳过设置用户参数")
return
}
// Firebase Analytics使用setUserProperty设置用户属性
params.forEach { (key, value) ->
try {
mFbAnalytics.setUserProperty(key, value.toString())
} catch (e: Exception) {
StatisticLogger.e("设置Firebase Analytics用户属性失败: $key = $value", e)
}
}
StatisticLogger.d("Firebase Analytics用户参数设置完成: ${mapToJson(params)}")
} catch (e: Exception) {
StatisticLogger.e("Firebase Analytics设置用户参数失败", e)
}
}
fun setCommonParams(params: Map<String, Any>) {
try {
// 如果获取为空,则异步等待阻塞获取
/*if (mFbAnalytics == null) {
StatisticLogger.d("Firebase Analytics未就绪开始异步等待...")
mFbAnalytics = runBlocking {
waitForFirebaseAnalytics()
}
}*/
if (mFbAnalytics == null) {
StatisticLogger.w("无法获取Firebase Analytics实例跳过设置公共参数")
return
}
// Firebase Analytics使用setDefaultEventParameters设置默认事件参数
val bundle = mapToBundle(params)
try {
mFbAnalytics.setDefaultEventParameters(bundle)
} catch (e: Exception) {
StatisticLogger.e("设置Firebase Analytics默认事件参数失败", e)
}
StatisticLogger.d("Firebase Analytics公共参数设置完成: ${mapToJson(params)}")
} catch (e: Exception) {
StatisticLogger.e("Firebase Analytics设置公共参数失败", e)
}
}
private fun mapToBundle(map: Map<String, Any>): Bundle {
val bundle = Bundle()
try {
map.forEach { (key, value) ->
when (value) {
is String -> bundle.putString(key, value)
is Int -> bundle.putInt(key, value)
is Long -> bundle.putLong(key, value)
is Double -> bundle.putDouble(key, value)
is Float -> bundle.putFloat(key, value)
is Boolean -> bundle.putBoolean(key, value)
else -> bundle.putString(key, value.toString())
}
}
} catch (e: Exception) {
StatisticLogger.e("Map转Bundle失败: ${e.message}")
}
return bundle
}
/**
* 将Map转换为JSON字符串用于日志
* @param map 要转换的Map
* @return JSON字符串
*/
private fun mapToJson(map: Map<String, Any>): String {
return try {
gson.toJson(map)
} catch (e: Exception) {
StatisticLogger.e("Map转JSON失败: ${e.message}")
"{}"
}
}
private suspend fun waitForFirebaseAnalytics(): FirebaseAnalytics? {
var attempts = 0
val maxAttempts = 10 // 最多尝试10次
val delayMs = 100L // 每次等待100ms
while (attempts < maxAttempts) {
val analytics = getFirebaseAnalytics()
if (analytics != null) {
return analytics
}
StatisticLogger.d("Firebase Analytics未就绪等待中... (${attempts + 1}/$maxAttempts)")
delay(delayMs)
attempts++
}
StatisticLogger.e("等待Firebase Analytics超时无法获取实例")
return null
}
private fun getFirebaseAnalytics(): FirebaseAnalytics? {
return try {
val context = BaseApp.appContext()
return FirebaseAnalytics.getInstance(context)
} catch (e: Exception) {
StatisticLogger.e("获取Firebase Analytics实例失败", e)
null
}
}
}

View File

@ -0,0 +1,165 @@
package com.gamedog.statisticreporter.shushu
import cn.thinkingdata.analytics.TDAnalytics
import cn.thinkingdata.analytics.TDAnalytics.TDAutoTrackEventType
import cn.thinkingdata.analytics.TDConfig
import cn.thinkingdata.analytics.ThinkingAnalyticsSDK
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.util.AndroidUtil.Companion.gson
import com.gamedog.statisticreporter.StatisticLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import org.json.JSONException
import org.json.JSONObject
class ShushuManager private constructor() {
companion object {
@Volatile
private var INSTANCE: ShushuManager? = null
fun instance(): ShushuManager {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: ShushuManager().also { INSTANCE = it }
}
}
}
private val mAppContext = BaseApp.appContext()
private val mBgScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val mMainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private lateinit var mShushuSdk: ThinkingAnalyticsSDK
fun initShushu(shushuAppId: String, shushuServerUrl: String) {
mMainScope.launch {
TDAnalytics.init(mAppContext, shushuAppId, shushuServerUrl)
val config = TDConfig.getInstance(mAppContext, shushuAppId, shushuServerUrl)
config.setMode(/*if (BuildConfig.DEBUG) TDConfig.ModeEnum.DEBUG else*/ TDConfig.ModeEnum.NORMAL)
mShushuSdk = ThinkingAnalyticsSDK.sharedInstance(config)
configAutoTrack()
}
}
/**
* 记录用户的具体行为事件
* 用户点击按钮浏览页面完成购买等
*/
fun reportEvent(eventKey: String, params: Map<String, Any>?, superProperties: Map<String, Any>) {
try {
TDAnalytics.setSuperProperties(JSONObject(superProperties))
val jsonObj = params?.let {
JSONObject(params)
}
TDAnalytics.track(eventKey, jsonObj)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 设置用户属性会覆盖同名属性
* 记录用户会员等级姓名等相对固定的属性
*/
fun reportUser() {
try {
val userProperties = JSONObject().apply {
put("user_level", "VIP3") // 用户等级
put("registration_date", "2025-01-01") // 注册日期
put("total_orders", 15) // 总订单数
}
TDAnalytics.userSet(userProperties)
} catch (e: JSONException) {
e.printStackTrace()
}
}
/**
* 设置全局事件属性自动附加到每个事件
* 应用版本号用户渠道来源等所有事件都带有的属性
*/
fun reportSuper() {
try {
val superProperties = JSONObject().apply {
put("app_version", "1.2.0")
put("channel", "xx应用市场")
put("user_city", "北京")
}
TDAnalytics.setSuperProperties(superProperties)
} catch (e: JSONException) {
e.printStackTrace()
}
}
/**
* 设置账号ID将后续行为关联到具体用户
* 用户登录成功时调用
*/
fun reportLogin(userUUID: String) {
TDAnalytics.login(userUUID)
}
//----------------------- PRIVATE ------------------------//
private fun configAutoTrack() {
TDAnalytics.enableAutoTrack(TDAutoTrackEventType.APP_START or TDAutoTrackEventType.APP_END or TDAutoTrackEventType.APP_INSTALL )
}
private fun mapToJsonObject(map: Map<String, Any>): JSONObject {
return try {
val jsonString = gson.toJson(map)
JSONObject(jsonString)
} catch (e: Exception) {
StatisticLogger.e("Map转JSONObject失败: ${e.message}")
JSONObject()
}
}
fun setCommonParams(params: Map<String, Any>) {
try {
// 将Map转换为JSONObject
val jsonObject = mapToJsonObject(params)
// 数数SDK使用userSet设置用户属性传入JSONObject
TDAnalytics.setSuperProperties(jsonObject)
StatisticLogger.d("数数SDK公共参数设置完成: $jsonObject")
} catch (e: Exception) {
StatisticLogger.e("数数SDK设置公共参数失败", e)
}
}
fun setUserParams(params: Map<String, Any>) {
try {
// 将Map转换为JSONObject
val jsonObject = mapToJsonObject(params)
// 数数SDK使用userSet设置用户属性传入JSONObject
TDAnalytics.userSet(jsonObject)
StatisticLogger.d("数数SDK用户参数设置完成: $jsonObject")
} catch (e: Exception) {
StatisticLogger.e("数数SDK设置用户参数失败", e)
}
}
}

View File

@ -0,0 +1,17 @@
package com.gamedog.statisticreporter
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

4
app/.gitignore vendored
View File

@ -1 +1,5 @@
/build /build
/release/baselineProfiles/0/app-release.dm
/release/baselineProfiles/1/app-release.dm
/release/output-metadata.json
/release/app-release.apk.zip

View File

@ -5,14 +5,16 @@ plugins {
// alias(libs.plugins.ksp) // alias(libs.plugins.ksp)
alias(libs.plugins.protobuf) alias(libs.plugins.protobuf)
id 'kotlin-kapt' id 'kotlin-kapt'
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
} }
android { android {
namespace = "com.gamedog.vididin" namespace = "com.viddin.videos.free"
compileSdk libs.versions.compileSdk.get().toInteger() compileSdk libs.versions.compileSdk.get().toInteger()
defaultConfig { defaultConfig {
applicationId "com.gamedog.vididin" applicationId "com.viddin.videos.free"
minSdk libs.versions.minSdk.get().toInteger() minSdk libs.versions.minSdk.get().toInteger()
targetSdk libs.versions.targetSdk.get().toInteger() targetSdk libs.versions.targetSdk.get().toInteger()
versionCode libs.versions.versionCode.get().toInteger() versionCode libs.versions.versionCode.get().toInteger()
@ -22,11 +24,22 @@ android {
} }
buildTypes { buildTypes {
release { debug {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' }
release {
minifyEnabled true
debuggable false
firebaseCrashlytics {
mappingFileUploadEnabled false
}
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
compileOptions { compileOptions {
sourceCompatibility libs.versions.javaVersion.get().toInteger() sourceCompatibility libs.versions.javaVersion.get().toInteger()
targetCompatibility libs.versions.javaVersion.get().toInteger() targetCompatibility libs.versions.javaVersion.get().toInteger()
@ -39,6 +52,10 @@ android {
} }
} }
kapt {
correctErrorTypes = true
}
protobuf { protobuf {
protoc { protoc {
@ -61,6 +78,9 @@ protobuf {
dependencies { dependencies {
implementation project(':base')
implementation project(':notification')
implementation libs.firebase.analytics
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.espresso.core)
@ -68,11 +88,8 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation(project(":core:network")) implementation(project(":core:network"))
implementation(project(":core:architecture")) implementation(project(":core:architecture"))
//api(project(":core:architecture-reflect")) implementation(project(":bill"))
implementation(project(":core:network")) implementation(project(":StatisticReporter"))
implementation(project(":youtube:core"))
implementation(project(":youtube:custom-ui"))
implementation libs.androidx.navigation.fragment.ktx implementation libs.androidx.navigation.fragment.ktx
implementation(libs.startup) implementation(libs.startup)
@ -83,11 +100,14 @@ dependencies {
implementation(libs.datastore) implementation(libs.datastore)
implementation(libs.protobuf.kotlin.lite) implementation(libs.protobuf.kotlin.lite)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation(libs.glide) // ImageLoader在用 implementation(libs.glide) // ImageLoader在用
implementation(libs.okhttp.logging) implementation(libs.okhttp.logging)
implementation(libs.retrofit) implementation(libs.retrofit)
implementation(libs.retrofit.kotlin.serialization) implementation(libs.retrofit.kotlin.serialization)
// implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:13.0.0'
// implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:custom-ui:13.0.0'
implementation(project(":youtube:core"))
implementation(project(":youtube:custom-ui"))
} }

53
app/config_debug.gradle Normal file
View File

@ -0,0 +1,53 @@
ext {
// AdMob配置
admob = [applicationId: "ca-app-pub-3392799053230605~7472226445", // IDAdMob应用ID
adUnitIds : [banner : "ca-app-pub-3392799053230605/2634832736",//"ca-app-pub-3392799053230605/6746479899",//"ca-app-pub-3940256099942544/9214589741", // "ca-app-pub-3392799053230605/6746479899" // 广ID // TODO- use pre test key
interstitial: "ca-app-pub-3392799053230605/5069601997", // 广ID
splash : "ca-app-pub-3392799053230605/5699979777", // 广ID
native : "ca-app-pub-3392799053230605/8969442262", // 广ID
full_native : "ca-app-pub-3392799053230605/6710110437", // 广ID
rewarded : "ca-app-pub-3392799053230605/9854847207" // 广ID
]]
// Pangle配置
pangle = [applicationId: "8757571", // Pangle测试应用ID
adUnitIds : [splash : "", // 广ID
banner : "", // 广ID320x50
interstitial: "982655945", // 广ID
native : "", // 广ID
full_native : "", // 广ID
rewarded : "982655960" // ID
]]
// TopOn配置
topon = [applicationId: "h1h0ukemtu13ak", // TopOn ID
appKey : "7d3af77b0803cbc641888cb393e8652e", // TopOn
adUnitIds : [ interstitial: "n1h0ukemvrnhn1", //"n1h0ukemvrnhn1", // 广 ID // TODO- if use this alway report error: placementId maybe is null
rewarded : "n1h0uken0i262r", // 广 ID
native : "", // 广 ID
splash : "", // 广 ID
full_native : "", // 广 ID
//banner : "" // 广 ID
]]
//
app = [applicationId: "com.viddin.videos.free",
compileSdk : 36,
minSdk : libs.versions.minSdk.get().toInteger(),
targetSdk : 36,
versionCode : 1,
versionName : "1.0.0"]
url = [privacyUrl: "https://www.google.com",
teamUrl : "https://www.google.com",]
//
analytics = [adjustAppToken: "sa8ei0td10xs", // Adjust App Token
thinkingDataAppId: "097b3fd67217437b83529c35f81a567e", // SDK APP ID
thinkingDataServerUrl: "https://data.tapvicogames.com", //
defaultUserChannel: "paid"] // internal默认paid
}

51
app/config_release.gradle Normal file
View File

@ -0,0 +1,51 @@
ext {
// AdMob配置 - Play
admob = [applicationId: "ca-app-pub-3392799053230605~7472226445", // IDAdMob应用ID
adUnitIds : [banner : "ca-app-pub-3392799053230605/2634832736", //"ca-app-pub-3392799053230605/6746479899", // 广ID
interstitial: "ca-app-pub-3392799053230605/5069601997", // 广ID
splash : "ca-app-pub-3392799053230605/5699979777", // 广ID
native : "ca-app-pub-3392799053230605/8969442262", // 广ID
full_native : "ca-app-pub-3392799053230605/6710110437", // 广ID
rewarded : "ca-app-pub-3392799053230605/9854847207" // 广ID
]]
// Pangle配置
pangle = [applicationId: "8757571", // Pangle测试应用ID
adUnitIds : [splash : "", // 广ID
banner : "", // 广ID320x50
interstitial: "982655945", // 广ID
native : "", // 广ID
full_native : "", // 广ID
rewarded : "982655960" // ID
]]
// TopOn配置
topon = [applicationId: "h1h0ukemtu13ak", // TopOn ID
appKey : "7d3af77b0803cbc641888cb393e8652e", // TopOn
adUnitIds : [ interstitial: "n1h0ukemvrnhn1", // 广 ID
rewarded : "n1h0uken0i262r", // 广 ID
native : "", // 广 ID
splash : "", // 广 ID
full_native : "", // 广 ID
banner : "" // 广 ID
]]
// - Play
app = [applicationId: "com.viddin.videos.free",
compileSdk : 36,
minSdk : libs.versions.minSdk.get().toInteger(),
targetSdk : 36,
versionCode : 1,
versionName : "1.0.0"]
url = [privacyUrl: "https://alifmd.com/privacy.html",
teamUrl : "https://alifmd.com/privacy.html",]
//
analytics = [adjustAppToken: "sa8ei0td10xs", // Adjust App Token
thinkingDataAppId: "097b3fd67217437b83529c35f81a567e", // SDK APP ID
thinkingDataServerUrl: "https://data.tapvicogames.com", //
defaultUserChannel: "paid"] // internal默认paid
}

29
app/google-services.json Normal file
View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "461028728722",
"project_id": "ag965e29930c-2d797-gp",
"storage_bucket": "ag965e29930c-2d797-gp.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:461028728722:android:e3c8d4a98e08f4e3f2eb4b",
"android_client_info": {
"package_name": "com.viddin.videos.free"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyA4pitzEQhu3VGg-VjOH-bWCEP2POYTDzA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

302
app/proguard-rules.pro vendored
View File

@ -19,3 +19,305 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
# ---------------------------------- 基础配置 ----------------------------------
# 代码优化次数通常设为5
-optimizationpasses 5
# 不使用混合大小写类名
-dontusemixedcaseclassnames
# 不忽略非公共库类
-dontskipnonpubliclibraryclasses
# 不进行预校验Android不需要可加快速度
-dontpreverify
# 打印混淆详情
-verbose
# 忽略警告
-ignorewarnings
# ---------------------------------- 保留重要属性 ----------------------------------
# 保留泛型签名重要避免JSON解析等类型转换错误
-keepattributes Signature
# 保留注解(如@Keep, @SerializedName等
-keepattributes *Annotation*
# 保留异常信息
-keepattributes Exceptions
# 保留源代码文件名和行号(便于崩溃日志分析)
-keepattributes SourceFile,LineNumberTable
# ---------------------------------- 保留Android基本组件 ----------------------------------
# 保留四大组件及其子类
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
# 保持 Native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保持 Parcelable 序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保持 Serializable 序列化的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保持自定义 View 的构造方法不被混淆(用于 XML 布局)
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
# 保持枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保持由 JSON 转换的 Bean 类(或者你的数据模型类)不被混淆
-keep class com.gamedog.vididin.beans.** { *; }
-keep class com.gamedog.vididin.router.** { *; }
# 保留R文件中的静态字段保证资源反射能正常工作
-keepclassmembers class **.R$* {
public static <fields>;
}
# gson
-keep class com.google.gson.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
# 明确保护被@SerializedName注解的字段
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
#okhttp
# OkHttp3
-dontwarn okhttp3.**
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okio.**
# Retrofit2
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature, Exceptions
#butter knife
# Butter Knife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
# ---------------------------------- 核心排除Bean/Model类防止JSON解析失败 ----------------------------------
# 规则:保护所有你定义的用于JSON序列化/反序列化的数据模型类JavaBean/POJO)不被混淆
# 替换 `com.yourpackage.model` 为你的数据模型类所在的实际包名
# 这将保护该包(及其子包)下所有类的类名字段名和方法名不被更改
-keep class com.gamedog.vididin.beans.** { *; }
-keep class com.viddin.videos.free.VidiDinApp { *; }
# 如果模型类实现了Serializable接口建议额外保留序列化版本UID和特定方法
-keepclassmembers class com.yourpackage.model.** implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# --------------------------------------------------
# Hilt 核心规则
# --------------------------------------------------
# 保留 Hilt 的注解处理器生成的类
-keep class dagger.hilt.internal.aggregatedroot.** { *; }
-keep class hilt_aggregated_deps.** { *; }
# 保留使用 @AndroidEntryPoint 注解的 Android 组件Activity, Fragment, View, Service, BroadcastReceiver
-keep class * extends android.app.Application { @dagger.hilt.android.AndroidEntryPoint <init>(); }
-keepclasseswithmembers class * { @dagger.hilt.android.AndroidEntryPoint <fields>; }
-keepclasseswithmembers class * { @dagger.hilt.android.AndroidEntryPoint <methods>; }
# 保留 Hilt 模块类,确保依赖提供逻辑不被混淆
-keep @dagger.Module class *
-keep @dagger.hilt.InstallIn class *
# 保留 Hilt 入口点EntryPoint相关的类
-keep @dagger.hilt.EntryPoint class *
-keepclassmembers @dagger.hilt.EntryPoint class * { *; }
# 保留 Hilt 生成的组件Component相关类
-keep @dagger.hilt.components.SingletonComponent class *
-keepclassmembers @dagger.hilt.components.SingletonComponent class * { *; }
# 保留 Hilt 处理器生成的工厂类
-keep class * extends dagger.internal.Binding { *; }
-keep class * extends dagger.internal.Factory { *; }
-keep class * implements dagger.MembersInjector { *; }
-keep class * implements dagger.Lazy { *; }
# 保留泛型信息,这对依赖注入很关键
-keepattributes Signature, InnerClasses, EnclosingMethod
# 保留注解信息Hilt 严重依赖注解)
-keepattributes *Annotation*
##############加密混淆###########
########腾讯X5内核浏览器中的的代码不被混淆#####
-keep class com.tencent.** {*;}
########RSA中的代码不被混淆
-keep class Decoder.** {*;}
-keep class org.bouncycastle.** {*;}
################Glide加载图片添加混淆
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
######## glide类库
######## com.github.bumptech.glide:okhttp3-integration:1.4.0@aar中的代码不被混淆
######## jp.wasabeef:glide-transformations:2.0.1 不被混淆
-keep class com.bumptech.** {*;}
-keep class jp.wasabeef.glide.** {*;}
########## 保证类库Image 中导入的jar包不被混淆
-keep class com.davemorrissey.** {*;}
-keep class com.filippudak.** {*;}
-keep class am.util.** {*;}
-keep class com.blankj.** {*;}
#########################################################第三方的配置结束#######################
#==================gson && protobuf==========================
-dontwarn com.google.**
-keep class com.google.gson.** {*;}
-keep class com.google.protobuf.** {*;}
#ProGuard 混淆
# keep住源文件以及行号
-keepattributes SourceFile,LineNumberTable
-keepattributes Signature
-dontwarn com.jcraft.jzlib.**
-keep class com.jcraft.jzlib.** { *;}
-dontwarn sun.misc.**
-keep class sun.misc.** { *;}
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *;}
-dontwarn sun.security.**
-keep class sun.security.** { *; }
-dontwarn com.google.**
-keep class com.google.** { *;}
-dontwarn com.avos.**
-keep class com.avos.** { *;}
-keep public class android.net.http.SslError
-keep public class android.webkit.WebViewClient
-dontwarn android.webkit.WebView
-dontwarn android.net.http.SslEr
-dontwarn android.webkit.WebViewClient
-dontwarn android.support.**
-dontwarn org.apache.**
-keep class org.apache.** { *;}
-dontwarn org.jivesoftware.smack.**
-keep class org.jivesoftware.smack.** { *;}
-dontwarn com.loopj.**
-keep class com.loopj.** { *;}
-dontwarn org.xbill.**
-keep class org.xbill.** { *;}
-keepattributes *Annotation*
# Gson
#gson
#如果用用到Gson解析包的直接添加下面这几行就能成功混淆不然会报错
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Application classes that will be serialized/deserialized over Gson
##---------------End: proguard configuration for Gson ----------
#基础混淆添加配置
-keepclassmembers class **.R$* {
public static <fields>;
public static final int *;
}
-keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆
public void *(android.view.View);
}
# bean目录
-keep class com.viddin.videos.free.VidiDinApp** {*;}
-keep class com.gamedog.vididin.beans.** {*;}
-keep class com.gamedog.vididin.manager.taskbeans.** {*;}
-keep class com.gamedog.vididin.router.** {*;}

View File

@ -2,7 +2,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE"/>
<application <application
android:name=".VidiDinApp" android:name=".VidiDinApp"
@ -14,27 +27,54 @@
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.Architectureandroid"> android:theme="@style/Theme.Architectureandroid">
<activity <activity
android:name=".main.MainActivity" android:name="com.gamedog.vididin.features.splash.SplashActivity"
android:exported="true"> android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.Transparent"
android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".login.LoginActivity" android:exported="false" /> <activity
<activity android:name=".features.benefit.BenefitActivity" android:exported="false" /> android:name="com.gamedog.vididin.main.MainActivity"
<activity android:name=".features.zero.ZeroBuyActivity" android:exported="false" /> android:screenOrientation="portrait" android:exported="true"
<activity android:name=".features.winrecords.WinRecordsActivity" android:exported="false" /> android:launchMode="singleTop" >
<activity android:name=".features.withdraw.WithDrawActivity" android:exported="false" /> </activity>
<activity android:name=".features.splash.SplashActivity" android:exported="false" />
<activity android:name=".features.version.VersionActivity" android:exported="false" /> <activity-alias
<activity android:name=".features.feedback.FeedbackActivity" android:exported="false" /> android:name="com.gamedog.vididin.main.MainActivityAlias"
<activity android:name=".features.withdrawrecord.WithdrawRecordActivity" android:exported="false" /> android:targetActivity="com.gamedog.vididin.main.MainActivity"
<activity android:name=".features.privacy.PrivacyActivity" android:exported="false" /> android:launchMode="singleTop"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="com.remax.notification.ACTION_OPEN_APP" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity-alias>
<activity android:name="com.gamedog.vididin.login.LoginActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.benefit.BenefitActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.zero.ZeroBuyActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.winrecords.WinRecordsActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.withdraw.WithDrawActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.withdraw.WithDrawSubActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.version.VersionActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.feedback.FeedbackActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.withdrawrecord.WithdrawRecordActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.privacy.PrivacyActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.game.GameCenterActivity" android:exported="false" />
<activity android:name="com.gamedog.vididin.features.watchad.WatchAdActivity"
android:theme="@style/Theme.Transparent"
android:screenOrientation="portrait"
android:exported="false" />
@ -46,6 +86,39 @@
android:name="com.gamedog.vididin.router.RouterInitializer" android:name="com.gamedog.vididin.router.RouterInitializer"
android:value="androidx.startup" /> android:value="androidx.startup" />
</provider> </provider>
<receiver
android:name="com.gamedog.vididin.manager.DateChangeReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
</receiver>
<receiver
android:name="com.remax.notification.newUtil.events.AppInstallReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name="com.remax.notification.newUtil.events.PowerConnectionReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@ -4,7 +4,10 @@
"module_name": "任务中心", "module_name": "任务中心",
"page_path": "底部第二个页签", "page_path": "底部第二个页签",
"layout_style": "上下滑动长页面", "layout_style": "上下滑动长页面",
"currency_display": ["金币账户", "巴西雷亚尔现金账户"] "currency_display": [
"金币账户",
"巴西雷亚尔现金账户"
]
}, },
"task_categories": [ "task_categories": [
{ {
@ -50,13 +53,34 @@
"target_action": "用户每日完成签到操作(支持广告补签)", "target_action": "用户每日完成签到操作(支持广告补签)",
"reward_type": "金币", "reward_type": "金币",
"reward_details": [ "reward_details": [
{"day": 1, "value": 100}, {
{"day": 2, "value": 300}, "day": 1,
{"day": 3, "value": 300}, "value": 100
{"day": 4, "value": 500}, },
{"day": 5, "value": 300}, {
{"day": 6, "value": 300}, "day": 2,
{"day": 7, "value": 800} "value": 300
},
{
"day": 3,
"value": 300
},
{
"day": 4,
"value": 500
},
{
"day": 5,
"value": 300
},
{
"day": 6,
"value": 300
},
{
"day": 7,
"value": 800
}
], ],
"support_makeup": true, "support_makeup": true,
"makeup_method": "观看15-30秒激励视频", "makeup_method": "观看15-30秒激励视频",
@ -78,13 +102,34 @@
"target_action": "用户当日完成签到操作", "target_action": "用户当日完成签到操作",
"reward_type": "金币", "reward_type": "金币",
"reward_details": [ "reward_details": [
{"day": 1, "value": 100}, {
{"day": 2, "value": 300}, "day": 1,
{"day": 3, "value": 300}, "value": 100
{"day": 4, "value": 500}, },
{"day": 5, "value": 300}, {
{"day": 6, "value": 300}, "day": 2,
{"day": 7, "value": 500} "value": 300
},
{
"day": 3,
"value": 300
},
{
"day": 4,
"value": 500
},
{
"day": 5,
"value": 300
},
{
"day": 6,
"value": 300
},
{
"day": 7,
"value": 500
}
], ],
"double_reward_method": "观看15-30秒激励视频", "double_reward_method": "观看15-30秒激励视频",
"support_makeup": true, "support_makeup": true,
@ -99,9 +144,18 @@
"target_action": "用户累计观看短视频", "target_action": "用户累计观看短视频",
"reward_type": "金币", "reward_type": "金币",
"reward_details": [ "reward_details": [
{"target_count": 10, "value": 100}, {
{"target_count": 20, "value": 150}, "target_count": 10,
{"target_count": 30, "value": 200} "value": 100
},
{
"target_count": 20,
"value": 150
},
{
"target_count": 30,
"value": 200
}
], ],
"reward_stackable": true, "reward_stackable": true,
"is_one_time": false, "is_one_time": false,
@ -114,9 +168,18 @@
"target_action": "用户累计观看激励视频", "target_action": "用户累计观看激励视频",
"reward_type": "金币", "reward_type": "金币",
"reward_details": [ "reward_details": [
{"target_count": 1, "value": 100}, {
{"target_count": 5, "value": 150}, "target_count": 1,
{"target_count": 10, "value": 200} "value": 100
},
{
"target_count": 5,
"value": 150
},
{
"target_count": 10,
"value": 200
}
], ],
"daily_limit": 10, "daily_limit": 10,
"reward_stackable": true, "reward_stackable": true,
@ -125,6 +188,104 @@
} }
] ]
} }
],
"box_task": {
"category_id": "bonuses_task",
"category_name": "福利宝箱Prémios únicos",
"valid_period": "每个宝箱持续3天完成对应任务即可领取现金奖励。",
"display_priority": 3,
"chests": [
{
"chest_id": "1",
"chest_name": "福利宝箱1",
"chest_desc": "完成福利宝箱1的全部任务后获得R$0.1现金奖励",
"duration_days": 3,
"reward_type": "货币",
"reward_value": 0.1,
"is_one_time": true,
"status": "active",
"tasks": [
{
"task_id": "chest1_task1",
"task_name": "观看1个广告",
"required_count": 1,
"task_type": 1
},
{
"task_id": "chest1_task2",
"task_name": "观看3个视频",
"required_count": 3,
"task_type": 2
},
{
"task_id": "chest1_task3",
"task_name": "完成1次签到",
"required_count": 1,
"task_type": 3
}
]
},
{
"chest_id": "2",
"chest_name": "福利宝箱2",
"chest_desc": "完成福利宝箱2的全部任务后获得R$1现金奖励",
"duration_days": 3,
"reward_type": "货币",
"reward_value": 1,
"is_one_time": true,
"status": "locked",
"tasks": [
{
"task_id": "chest2_task1",
"task_name": "观看15个广告",
"required_count": 15,
"task_type": 1
},
{
"task_id": "chest2_task2",
"task_name": "观看30个视频",
"required_count": 30,
"task_type": 2
},
{
"task_id": "chest2_task3",
"task_name": "参与1次0元购",
"required_count": 1,
"task_type": 4
}
]
},
{
"chest_id": "3",
"chest_name": "福利宝箱3",
"chest_desc": "完成福利宝箱3的全部任务后获得R$2现金奖励",
"duration_days": 3,
"reward_type": "货币",
"reward_value": 2,
"is_one_time": true,
"status": "locked",
"tasks": [
{
"task_id": "chest3_task1",
"task_name": "观看30个广告",
"required_count": 30,
"task_type": 1
},
{
"task_id": "chest3_task2",
"task_name": "观看50个视频",
"required_count": 50,
"task_type": 2
},
{
"task_id": "chest3_task3",
"task_name": "参与10次0元购",
"required_count": 10,
"task_type": 4
}
]
}
] ]
} }
} }
}

View File

@ -0,0 +1,130 @@
{
"task_module_config": {
"basic_info": {
"module_name": "任务中心",
"page_path": "底部第二个页签",
"layout_style": "上下滑动长页面",
"currency_display": ["金币账户", "巴西雷亚尔现金账户"]
},
"task_categories": [
{
"category_id": "newbie_task",
"category_name": "新手任务Missão Para Iniciantes",
"valid_period": "注册后7天内",
"display_priority": 1,
"tasks": [
{
"task_id": "newbie_first_withdraw",
"task_name": "完成第一次提现",
"task_desc": "完成首次提现操作0.1 BRL门槛即可获得100金币奖励",
"target_action": "用户完成首次提现流程含绑定Pix账户、观看广告",
"reward_type": "金币",
"reward_value": 100,
"is_one_time": true,
"status": "active"
},
{
"task_id": "newbie_push_notify",
"task_name": "开启消息推送",
"task_desc": "启用APP消息推送权限实时获取任务更新与奖励通知",
"target_action": "用户授权APP系统推送通知",
"reward_type": "金币",
"reward_value": 300,
"is_one_time": true,
"status": "active"
},
{
"task_id": "newbie_join_discord",
"task_name": "加入Discord社区",
"task_desc": "通过APP内链接加入官方Discord社区获取专属活动与客服支持",
"target_action": "用户通过指定链接成功加入Discord社区",
"reward_type": "金币",
"reward_value": 200,
"is_one_time": true,
"status": "active"
},
{
"task_id": "newbie_7day_checkin",
"task_name": "7日连续签到",
"task_desc": "连续7天完成签到奖励逐级递增第7天最高可得800金币",
"target_action": "用户每日完成签到操作(支持广告补签)",
"reward_type": "金币",
"reward_details": [
{"day": 1, "value": 100},
{"day": 2, "value": 300},
{"day": 3, "value": 300},
{"day": 4, "value": 500},
{"day": 5, "value": 300},
{"day": 6, "value": 300},
{"day": 7, "value": 800}
],
"support_makeup": true,
"makeup_method": "观看15-30秒激励视频",
"is_one_time": true,
"status": "active"
}
]
},
{
"category_id": "daily_task",
"category_name": "日常任务Missão Diária",
"valid_period": "每日凌晨00:00重置",
"display_priority": 2,
"tasks": [
{
"task_id": "daily_checkin",
"task_name": "每日签到",
"task_desc": "每日签到可获金币7天为一周期奖励循环递增支持双倍广告奖励",
"target_action": "用户当日完成签到操作",
"reward_type": "金币",
"reward_details": [
{"day": 1, "value": 100},
{"day": 2, "value": 300},
{"day": 3, "value": 300},
{"day": 4, "value": 500},
{"day": 5, "value": 300},
{"day": 6, "value": 300},
{"day": 7, "value": 500}
],
"double_reward_method": "观看15-30秒激励视频",
"support_makeup": true,
"makeup_method": "观看15-30秒激励视频",
"is_one_time": false,
"status": "active"
},
{
"task_id": "daily_video_ladder",
"task_name": "阶梯观看视频",
"task_desc": "累计观看指定数量短视频分3档领取奖励与基础观看收益叠加",
"target_action": "用户累计观看短视频",
"reward_type": "金币",
"reward_details": [
{"target_count": 10, "value": 100},
{"target_count": 20, "value": 150},
{"target_count": 30, "value": 200}
],
"reward_stackable": true,
"is_one_time": false,
"status": "active"
},
{
"task_id": "daily_ad_ladder",
"task_name": "阶梯观看激励视频",
"task_desc": "累计观看指定数量激励视频分3档领取奖励每日上限10次",
"target_action": "用户累计观看激励视频",
"reward_type": "金币",
"reward_details": [
{"target_count": 1, "value": 100},
{"target_count": 5, "value": 150},
{"target_count": 10, "value": 200}
],
"daily_limit": 10,
"reward_stackable": true,
"is_one_time": false,
"status": "active"
}
]
}
]
}
}

View File

@ -1,23 +0,0 @@
package com.gamedog.vididin
object VidiConst {
/**
* 描述网络常量
*
*/
const val URL_YOUTUBE_API = "https://www.googleapis.com"
/**
* 描述其他常量
*
*/
const val YOUTUBE_API_KEY = "AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY"
}

View File

@ -0,0 +1,114 @@
package com.gamedog.vididin
object VidiConst {
// adjust
const val GUIDE_INDEX_GIFT: Int = 1
const val GUIDE_INDEX_CASH_GOLD: Int = 2
const val GUIDE_INDEX_WITHDRAW: Int = 3
const val GUIDE_INDEX_ZERO: Int = 4
const val GUIDE_INDEX_POP_MENU: Int = 5
// adjust
const val ADJUST_TOKEN: String = "sa8ei0td10xs"
const val ADJUST_TOKEN_S2: String = "f3cff8c4bba54c6dc08b3401069ae06d"
const val ADJUST_WITHDRAW_SUCCESS_EVENT: String = "tjs3fp"
const val ADJUST_WITHDRAW_FAILED_EVENT: String = "33jp2j"
// shushu
const val SHUSHU_APP_ID: String = "097b3fd67217437b83529c35f81a567e"
const val SHUSHU_SERVER_URL: String = "https://data.tapvicogames.com"//"https://ss.zolnm.com"
const val NEWBIE_GIFT_GOLD_NUM: Long = 100
/**
* Varous type for watching Ad
*/
const val WATCH_AD_FOR_WITHDRAW_SMALL = 1
const val WATCH_AD_FOR_WITHDRAW_BIG = 2
const val WATCH_AD_FOR_BOX_TASK = 3
const val WATCH_AD_FOR_ZERO_EARN_DIAMOND = 4
const val WATCH_AD_FOR_DAILY_WATCH_AD = 5
const val WATCH_AD_FOR_DAILY_EARN_GOLD = 6
const val WATCH_AD_FOR_CONVERT_GOLD_2_CASH = 7
const val WATCH_AD_FOR_DAILY_SIGN_SINGLE = 8
const val WATCH_AD_FOR_DAILY_SIGN_DOUBLE = 9
const val WATCH_AD_FOR_DAILY_SIGN_COMPLEMENT = 10
const val WATCH_AD_FOR_DAILY_EARN_GOLD_POPMENU = 11
const val WATCH_AD_FOR_WATCHED_3_VIDEOS = 12
/**
* Withdraw related const
*/
const val WITHDRAW_MD5KEY = "eonline~#*^%$@!~0702"
/**
* zero buy related values
*/
const val ZERO_GET_PURCHASE_LIST: Int = 0
const val ZERO_JOIN_PURCHASE: Int = 10
const val ZERO_WITHDRAW_OPERATION: Int = 18
const val ZERO_WITHDRAW_RESULT_CHECK: Int = 2
const val URL_DISCORD: String = "https://discord.gg/qAZaaN8uaU"
const val URL_GAME: String = "https://s.gamifyspace.com/tml?pid=20057&appk=ZPfHlw7v5plM1N2moiiaDzixPszLSxIl&did=%s"
const val URL_PRIVACY: String = "https://rsappinc.com/privacy.html"
/**
* 描述网络常量
*
*/
const val URL_YOUTUBE_API = "https://vd.rsappinc.com"
const val URL_ZERO_BUY: String = "https://va.rsappinc.com" //"https://rsappinc.com" //
const val URL_WITHDRAW: String = "https://zz.rsappinc.com" //"https://jpec.3idiotstudio.com"
/**
* 描述其他常量
*
*/
const val YOUTUBE_API_KEY = "AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY"
const val GOLD_IN_CONFIG: String = "金币"
const val PER_01CASH_COST_GOLD_NUM = 100
const val WATCH_AD_REWARD_GOLD = 200
const val ZEROBUY_SECRET: String = "efda5260"//"1f04c57a"
const val DIAMOND_NUM_FOR_ONE_AD = 1
const val WITHDRAW_SMALL_NUM = 0.1F
const val WITHDRAW_REWARD_AD_REVENUE_PERCENT = 1.0
//------------------------ Statistics ----------------------------
const val STATISTICS_APP_OPEN = "app_open"
const val STATISTICS_NOTIFI_CLICK = "Notific_Click"
const val STATISTICS_NOTIFI_ENTER = "Notific_Enter"
}

View File

@ -1,25 +0,0 @@
package com.gamedog.vididin
import com.ama.core.architecture.BaseApp
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.manager.TaskManager
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class VidiDinApp : BaseApp() {
init {
}
override fun onCreate() {
super.onCreate()
initManagers()
}
private fun initManagers() {
AccountManager.getAccount()
TaskManager.instance()
}
}

View File

@ -0,0 +1,62 @@
package com.gamedog.vididin
object VidiStatisticHelper {
fun getShowFromStr(watchAdType: Int): String {
val fromStr = ""
when (watchAdType) {
VidiConst.WATCH_AD_FOR_WATCHED_3_VIDEOS -> {
return "RV_VideoStream"
}
VidiConst.WATCH_AD_FOR_DAILY_EARN_GOLD_POPMENU -> {
return "RV_Home_Menu"
}
VidiConst.WATCH_AD_FOR_DAILY_WATCH_AD -> {
return "RV_Daily_Task"
}
VidiConst.WATCH_AD_FOR_DAILY_EARN_GOLD -> {
return "RV_Coin"
}
VidiConst.WATCH_AD_FOR_CONVERT_GOLD_2_CASH -> {
return "RV_Exchange"
}
VidiConst.WATCH_AD_FOR_BOX_TASK -> {
return "Benefit_Task"
}
VidiConst.WATCH_AD_FOR_WITHDRAW_BIG -> {
return "RV_Accelerate2"
}
VidiConst.WATCH_AD_FOR_WITHDRAW_SMALL -> {
return "RV_Accelerate1"
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_SINGLE -> {
return "RV_Extra"
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_DOUBLE -> {
return "RV_Double"
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_COMPLEMENT -> {
return "RV_SupplementarySigning"
}
VidiConst.WATCH_AD_FOR_ZERO_EARN_DIAMOND -> {
return "RV_Zero_Diamond"
}
}
return fromStr
}
}

View File

@ -1,9 +1,66 @@
package com.gamedog.vididin package com.gamedog.vididin
object VididinEvents { object VididinEvents {
const val Event_Sign_State_Changed = 600 const val Event_Sign_State_Changed = 600
const val Event_Account_Gold_Changed = 601 const val Event_Account_Gold_Changed = 601
const val Event_Account_Cash_Changed = 602 const val Event_Account_Cash_Changed = 602
const val Event_Account_Bank_Info_Changed = 603 const val EVENT_BANK_INFO_CHANGED = 603
const val Event_Account_Diamond_Changed = 604
const val Event_HOME_WATCH_Time_TICK = 700
const val Event_Finish_One_Video = 701
const val EVENT_FINISHED_ONE_AD = 702
const val Event_Finish_One_Sign = 703
const val Event_Finish_One_Zerobuy = 704
const val EVENT_DAILY_WATCHED_VIDEO_NUM_CHANGED = 705
const val EVENT_DAILY_WATCHED_AD_NUM_CHANGED = 706
const val EVENT_BOX_TASK_STATE_CHANGED = 707
const val EVENT_NEWBIE_NOTIFY_TASK_CHANGED = 708
const val EVENT_NEWBIE_FIRST_WITHDRAW_TASK_CHANGED = 709
const val EVENT_NEWBIE_DISCORD_TASK_CHANGED = 710
const val EVENT_AD_WATCHED_FOR_CONVERT_GOLD_2_CASH = 800
const val EVENT_AD_WATCHED_FOR_EARN_GOLD = 801
const val EVENT_AD_WATCHED_FOR_DAILY_WATCH_AD = 802
const val Event_AD_TASK_TYPE_Withdraw = 803
const val Event_AD_TASK_TYPE_Complement = 804
const val EVENT_AD_WATCHED_FOR_BOX_TASK = 805
const val EVENT_AD_WATCHED_FOR_ZEROBUY_EARN_DIAMOND = 806
const val EVENT_AD_WATCHED_FOR_WITHDRAW_SMALL = 807
const val EVENT_AD_WATCHED_FOR_WITHDRAW_BIG = 808
const val EVENT_AD_WATCHED_FOR_DAILY_SIGN_SINGLE = 809
const val EVENT_AD_WATCHED_FOR_DAILY_SIGN_DOUBLE = 810
const val EVENT_AD_WATCHED_FOR_DAILY_SIGN_COMPLEMENT = 811
// UI jump related
const val EVENT_JUMP_2_FIRST_WITHDRAW = 900
const val EVENT_JUMP_2_VIDEO = 901
const val EVENT_JUMP_2_SIGN= 902
const val AD_ACT_SHOWING = 951
const val AD_ACT_DESTROY = 952
// Withdraw related
const val EVENT_WITHDRAW_SUB_ITEM_PROGRESS_UPDATED = 500
const val EVENT_WITHDRAW_SELECTED_SUB_ITEM_CHANGED = 501
const val EVENT_WITHDRAW_RESULT_UPDATED = 502
const val EVENT_WITHDRAW_ITEM_LIST_CHANGED = 503
const val EVENT_WITHDRAW_SMALL_AD_FINISHED = 504
// zero withdraw events
const val EVENT_ZERO_WITHDRAW_LIST_CHANGED = 200
} }

View File

@ -10,18 +10,18 @@ import androidx.viewpager2.widget.ViewPager2
import com.ama.core.architecture.appBase.adapter.AppNavigatorAdapter import com.ama.core.architecture.appBase.adapter.AppNavigatorAdapter
import com.ama.core.common.util.asSafe import com.ama.core.common.util.asSafe
import com.ama.core.common.util.getDataFromThemeAttr import com.ama.core.common.util.getDataFromThemeAttr
import com.gamedog.vididin.R
import com.gamedog.vididin.beans.MainTabsItem import com.gamedog.vididin.beans.MainTabsItem
import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener
import com.gamedog.vididin.main.interfaces.OnTabClickRefreshFinishListener import com.gamedog.vididin.main.interfaces.OnTabClickRefreshFinishListener
import com.gamedog.vididin.main.interfaces.OnTabClickRefreshListener import com.gamedog.vididin.main.interfaces.OnTabClickRefreshListener
import com.viddin.videos.free.R
import net.lucode.hackware.magicindicator.MagicIndicator import net.lucode.hackware.magicindicator.MagicIndicator
import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView
import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.CommonPagerTitleView import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.CommonPagerTitleView
import kotlin.ranges.until import kotlin.ranges.until
import com.gamedog.vididin.databinding.ItemActivityMainTabBinding as ViewBinding import com.viddin.videos.free.databinding.ItemActivityMainTabBinding as ViewBinding
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
@ -103,10 +103,10 @@ class MainTabsAdapter(
} }
} }
private fun ViewBinding.onTabClickAgainHandle(index: Int) { private fun ViewBinding.onTabClickAgainHandle(index: Int) {
val currentFragment = mainFragmentStateAdapter.getFragmentByIndex(index) val currentFragment = mainFragmentStateAdapter.getFragmentByIndex(index)
if (currentFragment is OnTabClickRefreshListener) { if (currentFragment is OnTabClickRefreshListener) {
// 刷新 - 展示Loading
currentFragment.onTabClickRefresh(object : OnTabClickRefreshFinishListener { currentFragment.onTabClickRefresh(object : OnTabClickRefreshFinishListener {
override fun onTabClickRefreshFinish() { override fun onTabClickRefreshFinish() {
setTabStyle(1) setTabStyle(1)

View File

@ -44,7 +44,7 @@ interface YoutubeApi {
): ResYoutubePlayList ): ResYoutubePlayList
@GET("/youtube/v3/videos") @GET("/youtube/v3/videos")
suspend fun getVideoList( suspend fun getVideoList_old(
@Query("part") part: String= URLEncoder.encode("snippet", "UTF-8"), @Query("part") part: String= URLEncoder.encode("snippet", "UTF-8"),
@Query("key") key: String= VidiConst.YOUTUBE_API_KEY, @Query("key") key: String= VidiConst.YOUTUBE_API_KEY,
@Query("videoDuration") videoDuration: String= "short", @Query("videoDuration") videoDuration: String= "short",
@ -56,10 +56,9 @@ interface YoutubeApi {
): ResYoutubePlayList ): ResYoutubePlayList
/* @GET("/videos")
https://www.googleapis.com/youtube/v3/videos?part=id&chart=mostPopular&regionCode=BR&maxResults=10&key=AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY suspend fun getVideoList(
https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics&chart=mostPopular&regionCode=BR&maxResults=10&key=AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY @Query("video") video: String? = URLEncoder.encode("", "UTF-8"),
*/ ): ResYoutubePlayList
} }

View File

@ -2,14 +2,25 @@ package com.gamedog.vididin.beans
data class Account( data class Account(
var userId: Int = 0,
var userName: String = "Miguel",
val accountId: String, val accountId: String,
val deviceUUId: String, val deviceUUId: String,
val token: String="", val token: String="",
val createdAt: Long, val createdAt: Long,
@Volatile
var goldCount: Long = 0L, var goldCount: Long = 0L,
var cashCount: Float = 0F, @Volatile
var cashCount: Double = 0.0,
@Volatile
var diamondCount: Int = 0,
var bankInfo: BankInfo? = null, var bankInfo: BankInfo? = null,
) val zeroBuyServerSecret: String = "",
var rvTimesGold: Int = 0,
var rvTimesCash: Int = 0,
) {
}
data class BankInfo( data class BankInfo(

View File

@ -0,0 +1,114 @@
package com.gamedog.vididin.beans
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DateUtil
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_FAIL
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_SUCCESS
import com.viddin.videos.free.R
// Record 类型
const val RECORD_CASH_PLUS_GOLD_CONVERT: Int = 1
const val RECORD_CASH_PLUS_BOX_TASK: Int = 2
const val RECORD_CASH_PLUS_WITHDRAW_ONGOING: Int = 3
const val RECORD_CASH_WITHDRAW: Int = 4
const val RECORD_CASH_ZERO_WITHDRAW_SUCCESS: Int = 5
abstract class BaseRecord {
var dateMs: Long = DateUtil.getCurTimeMs()
var uuid: String = AndroidUtil.randomUUid()
}
open class RecordCash (var recordType: Int = 0,
var amountNum: Double = 0.0,) : BaseRecord() {
// 提现相关的
var payInitItemId: Int = 0
var payOutReplyId: String = ""
var payOutReplyNo: String = ""
var withdrawState: Int = TRANSACTION_STATE_ONGOING // 提现状态 1:提现中,2:提现成功,3:提现失败
var withdrawFailType: Int = WithdrawManager.INIT_OK
var withdrawItemIndex: Int = -1
var withdrawItemLoopIndex: Int = -1
var withdrawItemSubIndex: Int = -1
var withdrawInitUUID: String = ""
var hasShowResultDialog: Boolean = false
}
class RecordCashShow: RecordCash() {
var title: Int = 0
var description: Int = 0
var iconRes: Int = 0
var textColor: Int = R.color.green_39
}
fun RecordCash.toShowBean(): RecordCashShow {
return RecordCashShow().apply {
this@apply.uuid = this@toShowBean.uuid
this@apply.dateMs = this@toShowBean.dateMs
this@apply.amountNum = this@toShowBean.amountNum
this@apply.recordType = this@toShowBean.recordType
this@apply.withdrawState = this@toShowBean.withdrawState
this@apply.withdrawFailType = this@toShowBean.withdrawFailType
when (this@apply.recordType) {
RECORD_CASH_PLUS_GOLD_CONVERT -> {
title = R.string.record_cash_title_convert_from_gold
description = R.string.record_cash_descr_convert_from_gold
iconRes = R.mipmap.task_gold
textColor = R.color.green_39
}
RECORD_CASH_PLUS_BOX_TASK -> {
title = R.string.record_cash_title_box
description = R.string.record_cash_descr_box
iconRes = R.mipmap.icon_gift
textColor = R.color.green_39
}
RECORD_CASH_PLUS_WITHDRAW_ONGOING -> {
title = R.string.record_cash_title_withdraw_ongoing
description = R.string.record_cash_descr_withdraw_onging
iconRes = R.mipmap.icon_convert_cash
textColor = R.color.red_28
}
RECORD_CASH_WITHDRAW -> {
this@apply.amountNum = -this@toShowBean.amountNum
when (withdrawState) {
TRANSACTION_STATE_ONGOING -> {
title = R.string.record_cash_title_withdraw_ongoing
description = R.string.record_cash_descr_withdraw_onging
iconRes = R.mipmap.icon_withdraw_ongoing
textColor = R.color.green_39
}
TRANSACTION_STATE_SUCCESS -> {
title = R.string.record_cash_title_withdraw_success
description = R.string.record_cash_descr_withdraw_success
iconRes = R.mipmap.icon_check
textColor = R.color.green_39
}
TRANSACTION_STATE_FAIL -> {
title = R.string.record_cash_title_withdraw_failed
description = WithdrawManager.instance().getFailHintStrRes(withdrawFailType)
iconRes = R.mipmap.icon_fail
textColor = R.color.gray3
}
}
}
RECORD_CASH_ZERO_WITHDRAW_SUCCESS -> {
title = R.string.record_cash_title_zero
description = R.string.record_cash_descr_zero
iconRes = R.mipmap.icon_zero
textColor = R.color.green_39
}
}
}
}

View File

@ -0,0 +1,103 @@
package com.gamedog.vididin.beans
import com.viddin.videos.free.R
import kotlin.Int
const val RECORD_GOLD_PLUS_WATCH_VIDEO_BY_TIME_DURATION: Int = 1
const val RECORD_GOLD_PLUS_WATCH_REWARD_AD: Int = 2
const val RECORD_GOLD_PLUS_NEWBIE_GIFT: Int = 3
const val RECORD_GOLD_PLUS_TASK_ENABLE_NOTIFY: Int = 4
const val RECORD_GOLD_PLUS_TASK_FIRST_WITHDRAW: Int = 5
const val RECORD_GOLD_PLUS_TASK_JOIN_DISCORD: Int = 6
const val RECORD_GOLD_PLUS_TASK_SIGN: Int = 7
const val RECORD_GOLD_PLUS_TASK_DAILY_AD: Int = 8
const val RECORD_GOLD_PLUS_TASK_DAILY_VIDEO: Int = 9
const val RECORD_GOLD_MINUS_CONVERT_2_CASH: Int = 10
open class RecordGold(var recordType: Int = 0, var amountNum: Long = 0): BaseRecord() {
var isSuccess: Boolean = false
}
class RecordGoldShow: RecordGold() {
var title: Int = 0
var description: Int = 0
var iconRes: Int = 0
}
fun RecordGold.toShowBean(): RecordGoldShow {
return RecordGoldShow().apply {
this@apply.uuid = this@toShowBean.uuid
this@apply.dateMs = this@toShowBean.dateMs
this@apply.isSuccess = this@toShowBean.isSuccess
this@apply.amountNum = this@toShowBean.amountNum
this@apply.recordType = this@toShowBean.recordType
when (this@apply.recordType) {
RECORD_GOLD_PLUS_WATCH_VIDEO_BY_TIME_DURATION -> {
title = R.string.record_gold_title_watch_video_time_duration
description = R.string.record_gold_descr_watch_video_time_duration
iconRes = R.mipmap.icon_video_task
}
RECORD_GOLD_PLUS_WATCH_REWARD_AD -> {
title = R.string.record_gold_title_watch_reward_ad
description = R.string.record_gold_descr_watch_reward_ad
iconRes = R.mipmap.icon_ad
}
RECORD_GOLD_PLUS_NEWBIE_GIFT -> {
title = R.string.record_gold_title_newbie_gift
description = R.string.record_gold_descr_newbie_gift
iconRes = R.mipmap.icon_gift
}
RECORD_GOLD_PLUS_TASK_ENABLE_NOTIFY -> {
title = R.string.record_gold_title_enable_notify
description = R.string.record_gold_descr_enable_notify
iconRes = R.mipmap.icon_notify
}
RECORD_GOLD_PLUS_TASK_FIRST_WITHDRAW -> {
title = R.string.record_gold_title_first_withdraw
description = R.string.record_gold_descr_first_withdraw
iconRes = R.mipmap.icon_dollar
}
RECORD_GOLD_PLUS_TASK_JOIN_DISCORD -> {
title = R.string.record_gold_title_join_discord
description = R.string.record_gold_descr_join_discord
iconRes = R.mipmap.icon_discord_2
}
RECORD_GOLD_PLUS_TASK_SIGN -> {
title = R.string.record_gold_title_sign
description = R.string.record_gold_descr_sign
iconRes = R.mipmap.icon_calendar
}
RECORD_GOLD_PLUS_TASK_DAILY_AD -> {
title = R.string.record_gold_title_daily_task_ad
description = R.string.record_gold_descr_daily_task_ad
iconRes = R.mipmap.icon_ad
}
RECORD_GOLD_PLUS_TASK_DAILY_VIDEO -> {
title = R.string.record_gold_title_daily_task_video
description = R.string.record_gold_descr_daily_task_video
iconRes = R.mipmap.icon_video_task
}
RECORD_GOLD_MINUS_CONVERT_2_CASH -> {
title = R.string.record_gold_title_convert_2_cash
description = R.string.record_gold_descr_convert_2_cash
iconRes = R.mipmap.icon_convert_cash
}
}
}
}

View File

@ -0,0 +1,31 @@
package com.gamedog.vididin.beans
import com.viddin.videos.free.R
open class RecordZero : BaseRecord() {
var isSuccess: Boolean = false
var amountNum: Double = 0.0
var recordType: Int = 0
}
class RecordZeroShow: RecordZero() {
var title: Int = 0
var description: Int = 0
var iconRes: Int = 0
}
fun RecordZero.toShowBean(): RecordZeroShow {
return RecordZeroShow().apply {
this@apply.uuid = this@toShowBean.uuid
this@apply.dateMs = this@toShowBean.dateMs
this@apply.isSuccess = this@toShowBean.isSuccess
this@apply.amountNum = this@toShowBean.amountNum
this@apply.recordType = this@toShowBean.recordType
when (this@apply.recordType) {
}
}
}

View File

@ -0,0 +1,10 @@
package com.gamedog.vididin.beans
data class WatchAdNotifyBean<T>(
var earnMoneyNum: Double = 0.0,
var extraData: T,
)

View File

@ -5,92 +5,20 @@ import com.ama.core.model.BaseFragmentStateDiffItem
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable
data class ResYoutubeChannel(
val id: String,
val name: String,
)
@Serializable @Serializable
data class ResYoutubePlayList ( data class ResYoutubePlayList (
val kind: String, val videos: List<YoutubeVideo>,
val etag: String, // TODO - this is Etag type
val nextPageToken: String,
val prevPageToken: String,
val pageInfo: PageInfo,
val items: List<YoutubeVideo>,
) )
@Serializable
data class PageInfo(
val totalResults: Int,
val resultsPerPage: Int,
)
@Serializable @Serializable
data class YoutubeVideo( data class YoutubeVideo(
val kind: String,
val etag: String,
val id: String, val id: String,
val snippet: Snippet, val channel_title: String,
val status: Status, val description: String,
val contentDetails: ContentDetails,
val player: Player,
val localizations: Localizations,
) : BaseFragmentStateDiffItem { ) : BaseFragmentStateDiffItem {
override fun getPrimaryKey() = id override fun getPrimaryKey() = id
override fun getItemId() = id.hashCode().toLong() override fun getItemId() = id.hashCode().toLong()
} }
@Serializable
data class ContentDetails(
val itemCount: Int,
)
@Serializable
data class Player(
val embedHtml: String,
)
@Serializable
data class Localizations(
val title: String,
val description: String,
)
@Serializable
data class Snippet(
val publishedAt: String,
val channelId: String,
val title: String,
val description: String,
//val thumbnails: Thumbnail,
val channelTitle: String,
val defaultLanguage: String,
val localized: Localized,
)
@Serializable
data class Localized(
val title: String,
val description: String,
)
@Serializable
data class Thumbnail(
val standard: String,
)
@Serializable
data class Status(
val privacyStatus: String,
val podcastStatus: Int,
)

View File

@ -0,0 +1,98 @@
package com.gamedog.vididin.beans
import com.ama.core.model.BaseFragmentStateDiffItem
import kotlinx.serialization.Serializable
@Serializable
data class ResYoutubeChannel(
val id: String,
val name: String,
)
/*
@Serializable
data class ResYoutubePlayList (
val kind: String,
val etag: String, // TODO - this is Etag type
val nextPageToken: String,
val prevPageToken: String,
val pageInfo: PageInfo,
val items: List<YoutubeVideo>,
)
@Serializable
data class PageInfo(
val totalResults: Int,
val resultsPerPage: Int,
)
@Serializable
data class YoutubeVideo(
val kind: String,
val etag: String,
val id: String,
val snippet: Snippet,
val status: Status,
val contentDetails: ContentDetails,
val player: Player,
val localizations: Localizations,
) : BaseFragmentStateDiffItem {
override fun getPrimaryKey() = id
override fun getItemId() = id.hashCode().toLong()
}
@Serializable
data class ContentDetails(
val itemCount: Int,
)
@Serializable
data class Player(
val embedHtml: String,
)
@Serializable
data class Localizations(
val title: String,
val description: String,
)
@Serializable
data class Snippet(
val publishedAt: String,
val channelId: String,
val title: String,
val description: String,
//val thumbnails: Thumbnail,
val channelTitle: String,
val defaultLanguage: String,
val localized: Localized,
)
@Serializable
data class Localized(
val title: String,
val description: String,
)
@Serializable
data class Thumbnail(
val standard: String,
)
@Serializable
data class Status(
val privacyStatus: String,
val podcastStatus: Int,
)
*/

View File

@ -0,0 +1,40 @@
package com.gamedog.vididin.beans
data class ZeroBuyResp (
val code: Int,
val message: String,
val user_id: Int,
val current_purchases : List<ZeroBuyItem>,
val finished_purchases : List<ZeroBuyItem>?,
val Content: String,
var contentObj: ZeroBuyItem?
)
data class ZeroBuyItem (
val id:Int = 0,
val title: String? = null,
val start_time:Long = 0,
val end_time:Long = 0,
val target_num:Int = 0,
val cost:Int = 0,
val price: String? = null,
val image:Int = 0,
val current_users: List<Int>? = null,
val winners: List<Int>? = null,
/*val redeem_code: String? = null,*/
val completed: Boolean = false,
)
data class ZeroBuyWithdrawResp (
val code: Int,
val message: String,
val content: String,
)

View File

@ -0,0 +1,31 @@
package com.gamedog.vididin.beans.req
import com.gamedog.vididin.beans.resp.PbReportDataAdjust
import com.gamedog.vididin.beans.resp.PbReportDataShuShu
open class PayInitReq (
var platform: String? = null,
var deviceid: String? = null,
var version: String? = null,
var ip: String? = null,
var ts: String? = null,
var sign: String? = null,
)
data class PayoutReq(
var account: String? = null,
var item_id: Int = 0,
var amount: String? = null,
var additional_remark: String? = null,
var uuid: String? = null,
var account_type: String? = null,
var document_type: String? = null,
var document_id: String? = null,
var name: String? = null,
var clientName: String? = null,
var dataAdjust: PbReportDataAdjust = PbReportDataAdjust(),
var dataShuShu: PbReportDataShuShu = PbReportDataShuShu(),
) : PayInitReq()
data class PayoutCheckReq(var record_no: String = "") : PayInitReq()

View File

@ -0,0 +1,107 @@
package com.gamedog.vididin.beans.resp
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
data class WithDrawRespData (
var items: MutableList<InitIem?>? = null,
var UUID: String? = null,
var IP: String? = null,
)
open class BaseReply (
var code: Int = 0,
var msg: String? = null
)
data class PayInit(var data: PayInitReply? = null) : BaseReply() {
}
open class PayInitReply (
var uuid: String? = null,
var items: List<InitIem?>? = null,
var days: Int = 0,
var error: Int = 0,
)
data class InitIem (
var id: Int = 0,
var amount: Float = 0f,
var status: Int = 0,
)
data class PbReportDataAdjust(
var gps_adid: String? = null, // 用户的gaid
var android_id: String? = null, // 原始安卓 ID
var adid: String? = null, // 与设备关联的 Adjust 标识符
var user_agent: String? = null, // 设备的User-Agent。必须进行 URL 编码。
var price: String? = null, // 客户端上报的价格 客户端上报的价格例如0.05
var currency: String? = null, // 货币单位 客户端上报的货币,例如
)
data class PbReportDataShuShu(
var gps_gaid: String? = null, // 用户的gaid
var android_id: String? = null ,// 原始安卓 ID
var adid: String? = null, // 与设备关联的 Adjust 标识符
var user_agent: String? = null, // 设备的User-Agent。必须进行 URL 编码
var price: String? = null, // 客户端上报的价格 客户端上报的价格例如0.05
var currency: String? = null, // 货币单位 客户端上报的货币例如USD
var payment_method: String? = null, // 收款方式 暂时只有一种pix
var payment_type: String? = null, // 账户形式 cpf/cnpj/evp/email/phone
var payment_number: String? = null, // 账户号码 收款账号号码
var iap_name: String? = null, // 商品名称 游戏侧自定义的提现项目名称例如0.1br/50br/100br
var gamecoin_number: String? = null, // 提现消耗的虚拟货币数 提现消耗的虚拟货币数量例如1500
var gamecoin_type: String? = null, // 提现消耗的虚拟货币类型 金币或钞票例如coin/money
var ss_account_id: String? = null, // 数数账号ID 用户的登录ID(如果需要接入数数请务必传此值)
var ss_distinct_id: String? = null, // 数数访客ID 用户在未登录状态下的ID(如果需要接入数数请务必传此值)
var ss_super_properties: String? = null, // 数数的公共属性和预制属性 json字符串
)
data class PayoutData(
var data: PayoutReply? = null
) : BaseReply()
data class PayoutReply (
var id: String? = null,
var record_no: String = "",
var error: Int = 0,
)
data class PayoutCheckData(var data: PayoutCheck? = null) : BaseReply()
data class PayoutCheck(
var status: Int = 0, // 提现状态 1:提现中,2:提现成功,3:提现失败
var error: Int = 0, // 错误码0成功1失败2签名验证失败3客户端版本过低4 ts长度错误
)
/*
data class WithdrawRecord (
var payOutReplyId: String = "",
var payOutReplyNo: String = "",
var cashNum: Double = 0.0,
var operateMs: Long = 0L,
var state: Int = TRANSACTION_STATE_ONGOING, // 提现状态 1:提现中,2:提现成功,3:提现失败
var failReason: Int = 0, // TODO - define various fail reasons
var withdrawItemIndex: Int = 0,
var withdrawItemSubIndex: Int = 0,
var hasShowResultDialog: Boolean = false
)*/

View File

@ -5,19 +5,27 @@ import com.gamedog.vididin.features.benefit.DefaultBenefitRouter
import com.gamedog.vididin.features.winrecords.DefaultWinRecordRouter import com.gamedog.vididin.features.winrecords.DefaultWinRecordRouter
import com.gamedog.vididin.features.winrecords.WinRecordRouter import com.gamedog.vididin.features.winrecords.WinRecordRouter
import com.gamedog.vididin.features.withdraw.DefaultWithdrawRouter import com.gamedog.vididin.features.withdraw.DefaultWithdrawRouter
import com.gamedog.vididin.features.withdraw.DefaultWithdrawSubRouter
import com.gamedog.vididin.features.withdraw.WithdrawRouter import com.gamedog.vididin.features.withdraw.WithdrawRouter
import com.gamedog.vididin.features.withdraw.WithdrawSubRouter
import com.gamedog.vididin.features.zero.DefaultZeroBuyRouter import com.gamedog.vididin.features.zero.DefaultZeroBuyRouter
import com.gamedog.vididin.features.zero.ZeroBuyRouter import com.gamedog.vididin.features.zero.ZeroBuyRouter
import com.gamedog.vididin.router.DefaultFeedbackRouter import com.gamedog.vididin.router.DefaultFeedbackRouter
import com.gamedog.vididin.router.DefaultGameRouter
import com.gamedog.vididin.router.DefaultMainRouter
import com.gamedog.vididin.router.DefaultPrivacyRouter import com.gamedog.vididin.router.DefaultPrivacyRouter
import com.gamedog.vididin.router.DefaultSplashRouter import com.gamedog.vididin.router.DefaultSplashRouter
import com.gamedog.vididin.router.DefaultVersionRouter import com.gamedog.vididin.router.DefaultVersionRouter
import com.gamedog.vididin.router.DefaultWatchAdRouter
import com.gamedog.vididin.router.DefaultWithdrawRecordRouter import com.gamedog.vididin.router.DefaultWithdrawRecordRouter
import com.gamedog.vididin.router.IRouterFeedback import com.gamedog.vididin.router.IRouterFeedback
import com.gamedog.vididin.router.IRouterGame
import com.gamedog.vididin.router.IRouterPrivacy import com.gamedog.vididin.router.IRouterPrivacy
import com.gamedog.vididin.router.IRouterSplash import com.gamedog.vididin.router.IRouterSplash
import com.gamedog.vididin.router.IRouterVersion import com.gamedog.vididin.router.IRouterVersion
import com.gamedog.vididin.router.IRouterWithdrawRecord import com.gamedog.vididin.router.IRouterWithdrawRecord
import com.gamedog.vididin.router.IRouterWatchAd
import com.gamedog.vididin.router.MainRouter
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -51,6 +59,15 @@ object WithdrawModule {
fun provideRouter(): WithdrawRouter = DefaultWithdrawRouter() fun provideRouter(): WithdrawRouter = DefaultWithdrawRouter()
} }
@Module
@InstallIn(SingletonComponent::class)
object WithdrawSubModule {
@Provides
@Singleton
fun provideRouter(): WithdrawSubRouter = DefaultWithdrawSubRouter()
}
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object WinRecordModule { object WinRecordModule {
@ -59,6 +76,14 @@ object WinRecordModule {
fun provideRouter(): WinRecordRouter = DefaultWinRecordRouter() fun provideRouter(): WinRecordRouter = DefaultWinRecordRouter()
} }
@Module
@InstallIn(SingletonComponent::class)
object MainModule {
@Provides
@Singleton
fun provideRouter(): MainRouter = DefaultMainRouter()
}
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
@ -68,6 +93,14 @@ object PrivacyModule {
fun provideRouter(): IRouterPrivacy = DefaultPrivacyRouter() fun provideRouter(): IRouterPrivacy = DefaultPrivacyRouter()
} }
@Module
@InstallIn(SingletonComponent::class)
object PrivacyGame {
@Provides
@Singleton
fun provideRouter(): IRouterGame = DefaultGameRouter()
}
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object FeedbackModule { object FeedbackModule {
@ -99,3 +132,11 @@ object VersionModule {
@Singleton @Singleton
fun provideRouter(): IRouterVersion = DefaultVersionRouter() fun provideRouter(): IRouterVersion = DefaultVersionRouter()
} }
@Module
@InstallIn(SingletonComponent::class)
object WatchAd {
@Provides
@Singleton
fun provideRouter(): IRouterWatchAd = DefaultWatchAdRouter()
}

View File

@ -2,6 +2,8 @@ package com.gamedog.vididin.core.network.di
import android.util.Log import android.util.Log
import com.ama.core.architecture.util.DeviceUtil
import com.gamedog.vididin.request.RequestUtil
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
@ -24,26 +26,23 @@ class GlobalInterceptor : Interceptor {
val emptyBody = "{}".toRequestBody("application/json;charset=utf-8".toMediaType()) val emptyBody = "{}".toRequestBody("application/json;charset=utf-8".toMediaType())
val requestBody = if (bodyStr.isNotBlank()) request.body else emptyBody val requestBody = if (bodyStr.isNotBlank()) request.body else emptyBody
val timeSec = RequestUtil.getTimestampSec()
val headersBuilder = Headers.Builder() val requestBuilder = chain.request().newBuilder()
/* .addHeader("User-Agent", "Android")
.add("authorazation", "Bearer xxxxx") .addHeader("Accept-Language", Locale.getDefault().toLanguageTag())
.add("AUTH_DID", AppUtils.getAndroidID()) .addHeader("Content-Type", "application/json")
.add("platform", AppConstant.APP_CLIENT) .addHeader("Accept", "application/json")
.add("Authorization", "Bearer xxx") .addHeader("Accept-Charset", "utf-8")
.add("versionNum", "100") // server real defined
*/ .addHeader("ApplicationId", RequestUtil.Request_APPId)
.add("User-Agent", "Android") .addHeader("Timestamp", timeSec.toString())
.add("Accept-Language", Locale.getDefault().toLanguageTag()) .addHeader("Sign", RequestUtil.getRequestSign(timeSec))
.add("Content-Type", "application/json") .addHeader("DeviceId", DeviceUtil.generateDeviceId())
.add("Accept", "application/json") .addHeader("authorazation", "Bearer xxxxx")
.add("Accept-Charset", "utf-8")
request = requestBuilder.build()
val headers = headersBuilder.build()
request = chain.request().newBuilder()
.headers(headers)
.build()
val response = chain.proceed(request) val response = chain.proceed(request)

View File

@ -0,0 +1,99 @@
package com.gamedog.vididin.core.network.di
import android.util.Log
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DeviceUtil
import com.gamedog.vididin.request.RequestUtil
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.asResponseBody
import okio.Buffer
import java.io.IOException
import java.util.Locale
class GlobalInterceptor2 : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val bodyStr = readBody(chain.request().body)
val emptyBody = "{}".toRequestBody("application/json;charset=utf-8".toMediaType())
val requestBody = if (bodyStr.isNotBlank()) request.body else emptyBody
val requestBuilder = chain.request().newBuilder()
.addHeader("User-Agent", "Android")
.addHeader("Accept-Language", Locale.getDefault().toLanguageTag())
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("Accept-Charset", "utf-8")
// server real defined
.addHeader("ApplicationId", AndroidUtil.getPackageId())
.addHeader("DeviceId", DeviceUtil.generateDeviceId())
.addHeader("authorazation", "Bearer xxxxx")
request = requestBuilder.build()
val response = chain.proceed(request)
if (true) {
try {
val contentStr = clone(response.body)?.string()
Log.d("RetroLog" ,
"""
请求 Start
${request.url}
******** 请求头 ${request.method} ********
${getRequestHeadersString(request)}
******** 请求体(当post等时) ********
${readBody(requestBody)}
******** 请求响应 ********
$contentStr
请求 End
""".trimIndent()
)
} catch (e: Exception) {
Log.d("RetroLog" , "GlobalInterceptor request.exception : ${e.localizedMessage}}")
}
}
return response
}
fun getRequestHeadersString(request: Request): String {
val headers = request.headers
val headerCount = headers.size
val sb = StringBuilder()
for (i in 0 until headerCount) {
val key = headers.name(i)
val value = headers.value(i)
sb.append("$key=$value\n")
}
return sb.toString()
}
private fun readBody(body: RequestBody?): String {
val buffer = Buffer()
body?.writeTo(buffer)
return buffer.readUtf8()
}
@Throws(IOException::class)
private fun clone(body: ResponseBody?): ResponseBody? {
val source = body?.source()
if (source?.request(Long.MAX_VALUE) == true) throw IOException("body too long!")
val bufferedCopy = source?.buffer?.clone()
return bufferedCopy?.asResponseBody(body.contentType(), body.contentLength())
}
}

View File

@ -45,7 +45,6 @@ internal object NetworkModule {
@Provides @Provides
@Singleton @Singleton
fun providesRetrofit( fun providesRetrofit(
networkJson: Json,
okhttpCallFactory: dagger.Lazy<Call.Factory>, okhttpCallFactory: dagger.Lazy<Call.Factory>,
): Retrofit { ): Retrofit {
return Retrofit.Builder() return Retrofit.Builder()

View File

@ -7,12 +7,16 @@ import com.gamedog.vididin.core.router.interfaces.TaskRouter
import com.gamedog.vididin.features.benefit.BenefitRouter import com.gamedog.vididin.features.benefit.BenefitRouter
import com.gamedog.vididin.features.winrecords.WinRecordRouter import com.gamedog.vididin.features.winrecords.WinRecordRouter
import com.gamedog.vididin.features.withdraw.WithdrawRouter import com.gamedog.vididin.features.withdraw.WithdrawRouter
import com.gamedog.vididin.features.withdraw.WithdrawSubRouter
import com.gamedog.vididin.features.zero.ZeroBuyRouter import com.gamedog.vididin.features.zero.ZeroBuyRouter
import com.gamedog.vididin.router.IRouterFeedback import com.gamedog.vididin.router.IRouterFeedback
import com.gamedog.vididin.router.IRouterGame
import com.gamedog.vididin.router.IRouterPrivacy import com.gamedog.vididin.router.IRouterPrivacy
import com.gamedog.vididin.router.IRouterSplash import com.gamedog.vididin.router.IRouterSplash
import com.gamedog.vididin.router.IRouterVersion import com.gamedog.vididin.router.IRouterVersion
import com.gamedog.vididin.router.IRouterWithdrawRecord import com.gamedog.vididin.router.IRouterWithdrawRecord
import com.gamedog.vididin.router.IRouterWatchAd
import com.gamedog.vididin.router.MainRouter
import dagger.hilt.EntryPoint import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
@ -30,14 +34,18 @@ interface RouterEntryPoint {
fun benefitRouter(): BenefitRouter fun benefitRouter(): BenefitRouter
fun zeroBuyRouter(): ZeroBuyRouter fun zeroBuyRouter(): ZeroBuyRouter
fun withdrawRouter(): WithdrawRouter fun withdrawRouter(): WithdrawRouter
fun withdrawSubRouter(): WithdrawSubRouter
fun winRecordBuyRouter(): WinRecordRouter fun winRecordBuyRouter(): WinRecordRouter
fun mainRouter(): MainRouter
fun privacyRouter(): IRouterPrivacy fun privacyRouter(): IRouterPrivacy
fun GameRouter(): IRouterGame
fun versionRouter(): IRouterVersion fun versionRouter(): IRouterVersion
fun feedbackRouter(): IRouterFeedback fun feedbackRouter(): IRouterFeedback
fun splashRouter(): IRouterSplash fun splashRouter(): IRouterSplash
fun withdrawRecordRouter(): IRouterWithdrawRecord fun withdrawRecordRouter(): IRouterWithdrawRecord
fun watchAdRouter(): IRouterWatchAd
} }

View File

@ -2,13 +2,35 @@ package com.gamedog.vididin.features.benefit
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.activity.viewModels import androidx.activity.viewModels
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.eventbus.NotifyMan
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.viddin.videos.free.R
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.features.benefit.widget.BenefitTaskItemView
import com.gamedog.vididin.main.fragments.task.DailySignDialog
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.manager.TaskManager
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_AD
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_VIDEO
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_SIGN
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_ZERO_BUY
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityBenefitBinding as ViewBinding import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_FINISH
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_CLAIMED
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_EXPIRED
import com.gamedog.vididin.router.Router
import com.viddin.videos.free.databinding.ActivityBenefitBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
@ -16,6 +38,8 @@ import com.gamedog.vididin.main.MainViewModel as ViewModel
@AndroidEntryPoint @AndroidEntryPoint
class BenefitActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class BenefitActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener {
private val mSubTaskViewList = mutableListOf<BenefitTaskItemView>()
override val mViewModel: ViewModel by viewModels() override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
@ -26,21 +50,35 @@ class BenefitActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnT
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
titlebar.setTitleText(R.string.benefit)
taskItem1.setActionFun { initViewsByTaskState()
gotoWatchVideo()
}
taskItem2.setActionFun {
gotoWatchVideo()
}
taskItem3.setActionFun {
gotoWatchVideo()
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val boxStatus = TaskManager.instance().boxTaskStatus()
val curSubBoxState = boxStatus.getCurrentBoxState()
val subTaskCount = curSubBoxState!!.tasks.size
val reward = curSubBoxState.reward_value
StatisticUtil.reportEvents(StatisticUtil.KEY_Welfare_Show, mapOf(
"total_amount" to reward,
"chest_count" to subTaskCount,
"task_type" to boxStatus.getCurrentBoxIndex().toString(),
"task_progress" to boxStatus.getCurrentBoxTotalProgress(),
))
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
registerEvents({ data->
when (data?.mEventType) {
VididinEvents.EVENT_BOX_TASK_STATE_CHANGED -> {
updateUI()
}
}
}, VididinEvents.EVENT_BOX_TASK_STATE_CHANGED)
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
@ -56,10 +94,188 @@ class BenefitActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnT
} }
private fun gotoWatchVideo() { private fun initViewsByTaskState() {
//TODO("Not yet implemented") initAddSubTaskViews()
updateSubTasksUI()
updateTopBoxesUI()
} }
private fun updateUI() {
updateSubTasksUI()
updateTopBoxesUI()
binding.counterdownTv.restartTimer()
}
private fun initAddSubTaskViews() {
val taskStateHelper = TaskManager.instance().boxTaskStatus()
var subTaskIndex = taskStateHelper.getCurrentBoxIndex()
if (subTaskIndex >= 0) {
val currentBoxState = taskStateHelper.getStatusBean().boxList[subTaskIndex]
currentBoxState.tasks.forEachIndexed { index, subTask ->
val separateLine = View(this@BenefitActivity)
separateLine.setBackgroundResource(R.color.gray_f2)
binding.llSubTaskContainer.addView(separateLine, ViewGroup.LayoutParams.MATCH_PARENT, ResUtil.getPixelSize(R.dimen.dp1))
val subTaskView = BenefitTaskItemView(this@BenefitActivity)
subTaskView.setActionFun { handleActionButClicked(subTask.task_type) }
val subViewParam = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
subViewParam.topMargin = ResUtil.getPixelSize(R.dimen.dp10)
subViewParam.bottomMargin = ResUtil.getPixelSize(R.dimen.dp10)
binding.llSubTaskContainer.addView(subTaskView, subViewParam)
mSubTaskViewList.add(subTaskView)
}
}
}
private fun handleActionButClicked(taskType: Int) {
when (taskType) {
BOX_SUB_TASK_TYPE_AD -> {
Router.WatchAd.startActivity(this@BenefitActivity, VidiConst.WATCH_AD_FOR_BOX_TASK)
}
BOX_SUB_TASK_TYPE_SIGN -> {
DailySignDialog(this@BenefitActivity).show()
}
BOX_SUB_TASK_TYPE_VIDEO -> {
finish()
NotifyMan.instance().sendEvent(VididinEvents.EVENT_JUMP_2_VIDEO, null)
}
BOX_SUB_TASK_TYPE_ZERO_BUY -> {
Router.ZeroBuy.startActivity(this@BenefitActivity)
}
}
}
private fun updateSubTasksUI() {
val taskStateHelper = TaskManager.instance().boxTaskStatus()
val currentBoxIndex = taskStateHelper.getCurrentBoxIndex()
val subTaskStateList = taskStateHelper.getStatusBean().boxList[currentBoxIndex].tasks
if (subTaskStateList.size == mSubTaskViewList.size) {
mSubTaskViewList.forEachIndexed { index, view ->
view.updateUIByState(subTaskStateList[index], currentBoxIndex,index)
}
}
}
private fun updateTopBoxesUI() {
val taskStateHelper = TaskManager.instance().boxTaskStatus()
val boxStateList = taskStateHelper.getStatusBean().boxList
with (binding) {
boxStateList.forEachIndexed { index, curBoxState ->
val stateEnum = taskStateHelper.getBoxStateEnum(index)
if (index == 0) {
ivSubtask1.setImageResource(getIconResByState(stateEnum))
tvSubtask1State.setText(getStrResByState(stateEnum))
tvSubtask1State.setTextColor(getStrColorByState(stateEnum))
with (tvSubtask1Reward) {
compoundDrawablePadding = if (stateEnum == STATE_CLAIMED) 0 else ResUtil.getPixelSize(R.dimen.dp3)
val tvRewardIcon = getRewardTvDrawableRes(stateEnum)
setCompoundDrawablesWithIntrinsicBounds(ResUtil.getDrawable(tvRewardIcon), null, null, null)
val needShowNum = R.mipmap.icon_check_mark != tvRewardIcon
setText(if (needShowNum) { ResUtil.getString(R.string.cash) + " " + curBoxState.reward_value} else "")
//setText(ResUtil.getString(R.string.cash) + " " + curBoxState.reward_value)
}
}
if (index == 1) {
ivSubtask2.setImageResource(getIconResByState(stateEnum))
tvSubtask2State.setText(getStrResByState(stateEnum))
tvSubtask2State.setTextColor(getStrColorByState(stateEnum))
with (tvSubtask2Reward) {
compoundDrawablePadding = if (stateEnum == STATE_FINISH || stateEnum == STATE_CLAIMED) 0 else ResUtil.getPixelSize(R.dimen.dp3)
val tvRewardIcon = getRewardTvDrawableRes(stateEnum)
setCompoundDrawablesWithIntrinsicBounds(ResUtil.getDrawable(tvRewardIcon), null, null, null)
val needShowNum = R.mipmap.icon_check_mark != tvRewardIcon
setText(if (needShowNum) { ResUtil.getString(R.string.cash) + " " + curBoxState.reward_value} else "")
}
}
if (index == 2) {
ivSubtask3.setImageResource(getIconResByState(stateEnum))
tvSubtask3State.setText(getStrResByState(stateEnum))
tvSubtask3State.setTextColor(getStrColorByState(stateEnum))
with (tvSubtask3Reward) {
compoundDrawablePadding = if (stateEnum == STATE_FINISH || stateEnum == STATE_CLAIMED) 0 else ResUtil.getPixelSize(R.dimen.dp3)
val tvRewardIcon = getRewardTvDrawableRes(stateEnum)
setCompoundDrawablesWithIntrinsicBounds(ResUtil.getDrawable(tvRewardIcon), null, null, null)
val needShowNum = R.mipmap.icon_check_mark != tvRewardIcon
setText(if (needShowNum) { ResUtil.getString(R.string.cash) + " " + curBoxState.reward_value} else "")
}
}
}
val couldClaimCashNum = taskStateHelper.getCouldClaimCashNum()
with (tvResgatar) {
if (couldClaimCashNum > 0) {
setBackgroundResource(R.mipmap.bg_but_green_long)
isClickable = true
} else {
setBackgroundResource(R.mipmap.but_bg_grady)
isClickable = false
}
setOnClickListener {
if (taskStateHelper.executeClaimCash()) {
//AndroidUtil.showToast(String.format(ResUtil.getString(R.string.has_claim_box_cash_hint), couldClaimCashNum))
AndroidUtil.showCustomToast(String.format(ResUtil.getString(R.string.has_claim_box_cash_hint), couldClaimCashNum))
}
}
}
// 总进度条, 奖励金额
val totalProgress = taskStateHelper.getCurrentBoxTotalProgress()
progressTasks.setProgress(totalProgress)
tvProgressNum.text = "($totalProgress%)"
tvHintRewardNum.text = buildString {
append(ResUtil.getString(R.string.cash))
append(" ")
append(taskStateHelper.getStatusBean().boxList[taskStateHelper.getCurrentBoxIndex()].reward_value)
}
}
}
private fun getIconResByState(state: Int): Int {
when (state) {
STATE_EXPIRED -> return R.mipmap.benefit_item_expired
STATE_FINISH, STATE_CLAIMED -> return R.mipmap.benefit_item_finished
else -> return R.mipmap.benefit_item_ongoing
}
}
private fun getStrResByState(state: Int): Int {
when (state) {
STATE_EXPIRED -> return R.string.expired
STATE_FINISH, STATE_CLAIMED -> return R.string.finished
else -> return R.string.ongoing
}
}
private fun getStrColorByState(state: Int): Int {
when (state) {
STATE_EXPIRED -> return R.color.gray_60
STATE_FINISH, STATE_CLAIMED -> return R.color.green_39
else -> return R.color.red_5c
}
}
private fun getRewardTvDrawableRes(state: Int): Int {
when (state) {
STATE_EXPIRED -> return R.mipmap.icon_cash_s_disable
STATE_CLAIMED -> return R.mipmap.icon_check_mark
else -> return R.mipmap.icon_cash_s
}
}
companion object { companion object {

View File

@ -5,7 +5,10 @@ import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.vididin.databinding.BenefitTaskItemViewBinding import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.BenefitTaskItemViewBinding
import com.gamedog.vididin.manager.TaskManager
import com.gamedog.vididin.manager.taskbeans.TaskStateBoxSub
class BenefitTaskItemView @JvmOverloads constructor( class BenefitTaskItemView @JvmOverloads constructor(
@ -40,11 +43,44 @@ class BenefitTaskItemView @JvmOverloads constructor(
} }
fun setProgressInfo(progress: String) { fun updateUIByState(subTaskState: TaskStateBoxSub, boxIndex: Int, subTaskIndex: Int) {
mBinding.tvProgressInfo.text = progress with (mBinding) {
val finishNum = if (subTaskState.finishedNum > subTaskState.required_count) subTaskState.required_count else subTaskState.finishedNum
val progressNum: Int = finishNum * 100 / subTaskState.required_count
var iconRes = R.mipmap.icon_video_task
when(subTaskState.task_type) {
1 -> { // ad
iconRes = R.mipmap.icon_ad
}
2-> { // video
iconRes = R.mipmap.icon_video_task
}
3 -> { // sign
iconRes = R.mipmap.icon_calendar
}
4-> { // zeroBuy
iconRes = R.mipmap.task_act_convi
}
}
ivItemIcon.setImageResource(iconRes)
tvItemTitle.setText(TaskManager.instance().boxTaskStatus().getSubTaskHintStrRes(boxIndex, subTaskIndex))
progressBar.setProgress(progressNum)
tvProgressInfo.text = "($finishNum/${subTaskState.required_count})"
with (tvAction) {
if (progressNum < 100) {
isClickable = true
setBackgroundResource( R.drawable.bg_benefit_item_action_bg)
setText(R.string.go_and_do)
} else {
isClickable = false
setBackgroundResource( R.drawable.bg_sub_task_disable)
setText(R.string.finished)
}
}
}
} }
} }

View File

@ -0,0 +1,65 @@
package com.gamedog.vididin.features.benefit.widget
import android.content.Context
import android.os.CountDownTimer
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import com.ama.core.architecture.util.DateUtil
import com.gamedog.vididin.manager.TaskManager
import com.viddin.videos.free.databinding.BenefitCountdownTimerViewBinding
class CounterDownTimerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private lateinit var mTimer: CountDownTimer
private var mBinding: BenefitCountdownTimerViewBinding
init {
mBinding = BenefitCountdownTimerViewBinding.inflate(LayoutInflater.from(context), this, true)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
startTimer()
}
private fun startTimer() {
val startMs = TaskManager.instance().boxTaskStatus().getCurrentBoxStartTimeMs()
val totalMs = TaskManager.instance().boxTaskStatus().getCurrentBoxTotalDurationMs()
val restMs = startMs + totalMs - System.currentTimeMillis()
mTimer = object : CountDownTimer(restMs, 1000) {
override fun onTick(millisUntilFinished: Long) {
val resultList = DateUtil.formatMs2HMS(millisUntilFinished)
mBinding.tvHour.text = resultList[0].toString()
mBinding.tvMin.text = resultList[1].toString()
mBinding.tvSecond.text = resultList[2].toString()
}
override fun onFinish() {
}
}.start()
}
fun restartTimer() {
if (mTimer != null) {
mTimer.cancel()
}
startTimer()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
if (mTimer != null) {
mTimer.cancel()
}
}
}

View File

@ -8,11 +8,14 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.gamedog.vididin.R import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.vididin.VidiConst
import com.viddin.videos.free.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityFeedbackBinding as ViewBinding import com.viddin.videos.free.databinding.ActivityFeedbackBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
@ -30,6 +33,14 @@ class FeedbackActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), On
titleBar.setTitleText(R.string.feedback, R.color.black) titleBar.setTitleText(R.string.feedback, R.color.black)
} }
setOnClickBatch(ivDiscord) {
when(this) {
ivDiscord -> {
AndroidUtil.openUrl(VidiConst.URL_DISCORD)
}
}
}
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {

View File

@ -0,0 +1,299 @@
package com.gamedog.vididin.features.game
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.view.LayoutInflater
import android.webkit.JavascriptInterface
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.appBase.AppViewsActivity
import com.ama.core.architecture.util.AndroidUtil
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel
import com.viddin.videos.free.databinding.ActivityGameBinding as ViewBinding
@AndroidEntryPoint
class GameCenterActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener {
override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override var mEnableBannerAd = false
private var mHasSendStatistic: Boolean = false
@SuppressLint("SetJavaScriptEnabled")
override fun ViewBinding.initViews() {
showLoading(false)
with(binding) {
titlebar.setBackIconColor(R.color.black)
titlebar.setTitleText(R.string.game_center, R.color.black)
onBackPressedDispatcher.addCallback(this@GameCenterActivity) {
if (webView.canGoBack()) {
webView.goBack()
} else {
finish()
}
}
with(webView) {
settings.javaScriptEnabled = true
webView.addJavascriptInterface(WebAppInterface(this@GameCenterActivity, webView), "com.viddin.videos.free")
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
if (!mHasSendStatistic) {
StatisticUtil.reportEvents(StatisticUtil.KEY_H5_Show)
mHasSendStatistic = true
}
hideLoading()
}
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest
): Boolean {
request.url?.let { url ->
if (!request.url.toString().startsWith("intent")) {
view?.loadUrl(url.toString())
return true
} else {
try {
handleIntentUrl(url.toString())
return true
} catch (e: Exception) {
e.printStackTrace()
}
}
}
return false
}
@Deprecated("For API level < 24")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (!url.isNullOrBlank() && !url.startsWith("intent")) {
view?.loadUrl(url)
return true
}
return false
}
}
}
loadGameCenterWeb()
}
}
private fun loadGameCenterWeb() {
var gaid: String? = ""
showLoading(false)
lifecycleScope.launch {
withContext(Dispatchers.IO) {
gaid = AndroidUtil.getGaid()
}
if (!gaid.isNullOrBlank()) {
binding.webView.loadUrl(String.format(VidiConst.URL_GAME, gaid))
hideLoading()
} else {
hideLoading()
}
}
}
override fun ViewBinding.initWindowInsets() {
setImmerseRootView(contentRoot)
}
override fun ViewBinding.initListeners() {
//TODO("Not yet implemented")
}
override fun ViewBinding.initObservers() {
//TODO("Not yet implemented")
}
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
//TODO("Not yet implemented")
}
override fun onTabIsDarkFont(isDarkFont: Boolean) {
//TODO("Not yet implemented")
}
private fun handleIntentUrl(url: String) {
var intent: Intent? = null
if (url.startsWith("intent")) {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
}
if (intent != null) {
if (isHw()) {
intent.setPackage(getDefaultBrowser())
}
intent.addCategory(Intent.CATEGORY_BROWSABLE)
intent.setComponent(null)
intent.setFlags(FLAG_ACTIVITY_NEW_TASK)
}
this.startActivity(intent)
}
fun isHw(): Boolean {
return "huawei".equals(Build.MANUFACTURER, ignoreCase = true)
}
fun getDefaultBrowser(): String? {
var packageName: String? = null
var systemApp: String? = null
var userApp: String? = null
val userAppList: MutableList<String?> = ArrayList<String?>()
val context: Context = BaseApp.appContext()
val browserIntent = Intent("android.intent.action.VIEW", Uri.parse("https://"))
val resolveInfo = context.getPackageManager()
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
if (resolveInfo != null && resolveInfo.activityInfo != null) {
packageName = resolveInfo.activityInfo.packageName
}
if (packageName == null || packageName == "android") {
val lists = context.getPackageManager().queryIntentActivities(browserIntent, 0)
for (app in lists) {
if ((app.activityInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0) {
systemApp = app.activityInfo.packageName
} else {
userApp = app.activityInfo.packageName
userAppList.add(userApp)
}
}
if (userAppList.contains("com.android.chrome")) {
packageName = "com.android.chrome"
} else {
if (systemApp != null) {
packageName = systemApp
}
if (userApp != null) {
packageName = userApp
}
}
}
return packageName
}
companion object {
internal fun startActivity(activity: Activity) {
activity.startActivity(Intent(activity.applicationContext, GameCenterActivity::class.java))
}
}
}
class WebAppInterface(private val context: Activity, private val webView: WebView) {
@JavascriptInterface
fun openBrowser(url: String) {
try {
var intent: Intent? = null
if (url.startsWith("intent")) {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
} else {
intent = Intent("android.intent.action.VIEW", Uri.parse(url))
}
if (intent != null) {
if (isHw()) {
intent.setPackage(getDefaultBrowser())
}
intent.addCategory(Intent.CATEGORY_BROWSABLE)
intent.setComponent(null)
intent.setFlags(FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
//点击互动广告关闭按钮时调用该方法。
@JavascriptInterface
fun close() {
//TODO close the ad page or activity.
}
//接入Gspace-Fully广告时需实现此方法。该方法用于打开新的Webview页面。
@JavascriptInterface
fun openWebview(url: String?) {
//TODO open a new page to display landingpage.
//TODO 使用展示GSpace的Activity新实例打开当前url.
}
fun isHw(): Boolean {
return "huawei".equals(Build.MANUFACTURER, ignoreCase = true)
}
fun getDefaultBrowser(): String? {
var packageName: String? = null
var systemApp: String? = null
var userApp: String? = null
val userAppList: MutableList<String?> = ArrayList<String?>()
val context: Context = BaseApp.appContext()
val browserIntent = Intent("android.intent.action.VIEW", Uri.parse("https://"))
val resolveInfo = context.getPackageManager()
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
if (resolveInfo != null && resolveInfo.activityInfo != null) {
packageName = resolveInfo.activityInfo.packageName
}
if (packageName == null || packageName == "android") {
val lists = context.getPackageManager().queryIntentActivities(browserIntent, 0)
for (app in lists) {
if ((app.activityInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0) {
systemApp = app.activityInfo.packageName
} else {
userApp = app.activityInfo.packageName
userAppList.add(userApp)
}
}
if (userAppList.contains("com.android.chrome")) {
packageName = "com.android.chrome"
} else {
if (systemApp != null) {
packageName = systemApp
}
if (userApp != null) {
packageName = userApp
}
}
}
return packageName
}
}

View File

@ -4,15 +4,13 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.gamedog.vididin.R import com.gamedog.vididin.VidiConst
import com.viddin.videos.free.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityPrivacyBinding as ViewBinding import com.viddin.videos.free.databinding.ActivityPrivacyBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
@ -28,17 +26,14 @@ class PrivacyActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnT
with(binding) { with(binding) {
titlebar.setBackIconColor(R.color.black) titlebar.setBackIconColor(R.color.black)
titlebar.setTitleText(R.string.privacy, R.color.black) titlebar.setTitleText(R.string.privacy, R.color.black)
webView.loadUrl(VidiConst.URL_PRIVACY)
} }
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(contentRoot)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {

View File

@ -1,62 +1,210 @@
package com.gamedog.vididin.features.splash package com.gamedog.vididin.features.splash
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import android.view.animation.LinearInterpolator
import androidx.core.view.ViewCompat import androidx.lifecycle.lifecycleScope
import androidx.core.view.WindowInsetsCompat import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import androidx.core.view.updatePadding import com.gamedog.statisticreporter.StatisticUtil
import com.ama.core.architecture.appBase.AppViewsActivity
import com.gamedog.vididin.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.router.Router
import com.remax.base.report.DataReportManager
import com.remax.bill.ads.AdResult
import com.remax.bill.ads.PreloadController
import com.remax.bill.ads.bidding.AppOpenBiddingInitializer
import com.remax.bill.ads.config.AdConfigManager
import com.remax.bill.ads.ext.AdShowExt
import com.remax.bill.ads.log.AdLogger
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlinx.coroutines.async
import com.gamedog.vididin.databinding.ActivitySplashBinding as ViewBinding import kotlinx.coroutines.delay
import com.gamedog.vididin.main.MainUiState as UiState import kotlinx.coroutines.launch
import com.gamedog.vididin.main.MainViewModel as ViewModel import kotlin.math.ceil
import com.viddin.videos.free.databinding.ActivitySplashBinding as ViewBinding
@AndroidEntryPoint @AndroidEntryPoint
class SplashActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class SplashActivity : AppViewsEmptyViewModelActivity<ViewBinding>(), OnTabStyleListener {
private var mHasGotoMain: Boolean = false
private var mStartMs: Long = 0L
private var isAdShowSuccess = false
private var startTime = 0L
override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initViews() { override var mEnableBannerAd = false
with(binding) {
override fun ViewBinding.initViews() {
startTime = System.currentTimeMillis()
with(binding) {
}
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mStartMs = System.currentTimeMillis()
StatisticUtil.reportEvents(StatisticUtil.KEY_Loading_Start, null)
}
override fun onDestroy() {
super.onDestroy()
StatisticUtil.reportEvents(StatisticUtil.KEY_Loading_End, mapOf("Time" to (System.currentTimeMillis() - mStartMs)/1000))
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(contentRoot)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
//TODO("Not yet implemented") startJumpTimer()
startLoadingAnim()
initializeApp()
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
//TODO("Not yet implemented")
}
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
//TODO("Not yet implemented")
} }
override fun onTabIsDarkFont(isDarkFont: Boolean) { override fun onTabIsDarkFont(isDarkFont: Boolean) {
//TODO("Not yet implemented")
}
private fun startJumpTimer() {
lifecycleScope.launch {
delay(MAX_SPLASH_TIME)
gotoMain(!isAdShowSuccess)
}
}
private fun initializeApp() {
lifecycleScope.launch() {
try {
val adMobInitDeferred = async { initializeAd() }
val adMobResult = adMobInitDeferred.await()
// 处理AdMob初始化结果
when (adMobResult) {
is AdResult.Success -> {
// 2. 加载开屏广告
showAppOpenAd()
}
is AdResult.Failure -> {
AdLogger.e("AdMob SDK初始化失败: ${adMobResult.error.message}")
// 初始化失败,延迟后直接跳转
delayAndJumpToMain(isAdShowSuccess)
}
AdResult.Loading -> {
AdLogger.d("AdMob SDK初始化中...")
}
}
} catch (e: Exception) {
AdLogger.e("应用初始化异常", e)
delayAndJumpToMain(isAdShowSuccess)
}
}
} }
private suspend fun initializeAd(): AdResult<Unit> {
return AppOpenBiddingInitializer.initialize(this@SplashActivity, R.mipmap.ic_launcher)
}
private suspend fun showAppOpenAd() {
when (val result = AdShowExt.showAppOpenAd(this@SplashActivity) { loaded ->
PreloadController.preload(this)
PreloadController.preloadPangle(this)
PreloadController.preloadTopOn(this)
DataReportManager.reportData(
"loading_page_end", mapOf(
"pass_time" to ceil((System.currentTimeMillis() - startTime) / 1000.0).toInt()
)
)
}) {
is AdResult.Success -> {
isAdShowSuccess = true
delayAndJumpToMain(false)
}
is AdResult.Failure -> {
AdLogger.e("开屏广告显示失败: ${result.error.message}")
// 开屏失败尝试展示插页
if (AdConfigManager.shouldShowInterstitialAfterAppOpenFailure()) {
lifecycleScope.launch {
try {
when (val interstitialResult = AdShowExt.showInterstitialAd(this@SplashActivity, "splash")) {
is AdResult.Success -> {
delayAndJumpToMain(true)
}
is AdResult.Failure -> {
delayAndJumpToMain(true)
}
AdResult.Loading -> {
}
}
} catch (e: Exception) {
delayAndJumpToMain(isAdShowSuccess)
}
}
} else {
delayAndJumpToMain(isAdShowSuccess)
}
}
AdResult.Loading -> {
AdLogger.d("开屏广告显示中...")
}
}
}
private suspend fun delayAndJumpToMain(needShowSplashAd: Boolean) {
val elapsedTime = System.currentTimeMillis() - startTime
val remainingTime = MIN_SPLASH_TIME - elapsedTime
if (remainingTime > 0) {
delay(remainingTime)
}
gotoMain(needShowSplashAd)
}
private fun gotoMain(needShowSplashAd: Boolean) {
if (!mHasGotoMain) {
mHasGotoMain = true
Router.Main.startActivity(this@SplashActivity, needShowSplashAd)
finish()
}
}
private fun startLoadingAnim() {
val imageView = binding.ivAnim
ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f).apply {
duration = 2000L
interpolator = LinearInterpolator()
repeatCount = ValueAnimator.INFINITE
start()
}
}
companion object { companion object {
const val MAX_SPLASH_TIME = 5 * 1000L
const val MIN_SPLASH_TIME = 2 * 1000L
internal fun startActivity(activity: Activity) { internal fun startActivity(activity: Activity) {
activity.startActivity(Intent(activity.applicationContext, SplashActivity::class.java)) activity.startActivity(Intent(activity.applicationContext, SplashActivity::class.java))
} }

View File

@ -4,19 +4,24 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat import androidx.core.view.isVisible
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.gamedog.vididin.R import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.SpUtil
import com.gamedog.vididin.beans.RecordGold
import com.gamedog.vididin.core.login.login.AccountManager
import com.viddin.videos.free.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.manager.TestingManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityVersionBinding as ViewBinding import com.viddin.videos.free.databinding.ActivityVersionBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
@AndroidEntryPoint @AndroidEntryPoint
class VersionActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class VersionActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener {
@ -28,17 +33,63 @@ class VersionActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnT
with(binding) { with(binding) {
titlebar.setBackIconColor(R.color.black) titlebar.setBackIconColor(R.color.black)
titlebar.setTitleText(R.string.version, R.color.black) titlebar.setTitleText(R.string.version, R.color.black)
tvVersion.text = AndroidUtil.getAppVersionInfo()
// For Testing
val shouldShowDebug = true//BuildConfig.DEBUG
llTesting.isVisible = shouldShowDebug
if (shouldShowDebug) {
butCash.setOnClickListener {
try {
val cashNum: Double = evCash.text.toString().toDouble()
AccountManager.adjustCash(cashNum, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
butGold.setOnClickListener {
try {
val goldNum = evGold.text.toString().toLong()
AccountManager.adjustGold(goldNum, RecordGold())
} catch (e: Exception) {
e.printStackTrace()
}
}
butDiamond.setOnClickListener {
try {
val diamondNum = evDiamond.text.toString().toInt()
AccountManager.adjustDiamond(diamondNum)
} catch (e: Exception) {
e.printStackTrace()
}
}
// ad
checkerRewardAd.isChecked = TestingManager.instance().isRewardAdDisable()
checkerNormalAd.isChecked = TestingManager.instance().isNormalAdDisable()
checkerRewardAd.setOnCheckedChangeListener {_, isChecked ->
SpUtil.instance().putBoolean(SpUtil.KEY_TESTING_REWARD_AD_DISABLE, isChecked)
}
checkerNormalAd.setOnCheckedChangeListener {_, isChecked ->
SpUtil.instance().putBoolean(SpUtil.KEY_TESTING_NORMAL_AD_DISABLE, isChecked)
}
}
} }
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(contentRoot)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {

View File

@ -0,0 +1,245 @@
package com.gamedog.vididin.features.watchad
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.view.LayoutInflater
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.eventbus.NotifyMan
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VidiStatisticHelper
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.WatchAdNotifyBean
import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.manager.TestingManager
import com.gamedog.vididin.manager.WithdrawItem
import com.remax.bill.ads.AdResult
import com.remax.bill.ads.ext.AdShowExt
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.ActivityWatchAdBinding as ViewBinding
@AndroidEntryPoint
class WatchAdActivity : AppViewsEmptyViewModelActivity<ViewBinding>(), OnTabStyleListener {
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
private var mIsLoadSuccess: Boolean = false
private var mRewardedDollarNum: Double = 0.0
override var mEnableBannerAd = false
private lateinit var mCountDownTimer: CountDownTimer
private var mWatchType: Int = 0
private var mExtraJsonStr: String? = null
override fun ViewBinding.initViews() {
with(binding) {
}
}
override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
}
override fun ViewBinding.initListeners() {
stateCounter()
showVideoAd()
}
private fun notifyAdWatchFinish() {
var notifyEventType = 0
var notifyData: NotifyMan.NotifyData<Any> = NotifyMan.NotifyData()
var shouldNotifyOneAdWatched = true
when (mWatchType) {
VidiConst.WATCH_AD_FOR_WITHDRAW_SMALL -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_SMALL
val extraData = mExtraJsonStr?.let {
AndroidUtil.json2Object<Float>(mExtraJsonStr!!)
}
notifyData.mData = WatchAdNotifyBean(mRewardedDollarNum, extraData)
}
VidiConst.WATCH_AD_FOR_WITHDRAW_BIG -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_BIG
val extraData = mExtraJsonStr?.let {
AndroidUtil.json2Object<WithdrawItem>(mExtraJsonStr!!)
}
notifyData.mData = WatchAdNotifyBean(mRewardedDollarNum, extraData)
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_SINGLE -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_DAILY_SIGN_SINGLE
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_DOUBLE-> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_DAILY_SIGN_DOUBLE
}
VidiConst.WATCH_AD_FOR_DAILY_SIGN_COMPLEMENT -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_DAILY_SIGN_COMPLEMENT
}
VidiConst.WATCH_AD_FOR_BOX_TASK -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_BOX_TASK
}
VidiConst.WATCH_AD_FOR_ZERO_EARN_DIAMOND -> {
shouldNotifyOneAdWatched = false
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_ZEROBUY_EARN_DIAMOND
}
VidiConst.WATCH_AD_FOR_WATCHED_3_VIDEOS, VidiConst.WATCH_AD_FOR_DAILY_WATCH_AD -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_DAILY_WATCH_AD
}
VidiConst.WATCH_AD_FOR_DAILY_EARN_GOLD_POPMENU, VidiConst.WATCH_AD_FOR_DAILY_EARN_GOLD -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_EARN_GOLD
}
VidiConst.WATCH_AD_FOR_CONVERT_GOLD_2_CASH -> {
shouldNotifyOneAdWatched = true
notifyEventType = VididinEvents.EVENT_AD_WATCHED_FOR_CONVERT_GOLD_2_CASH
}
}
NotifyMan.instance().sendEvent(notifyEventType, notifyData)
if (shouldNotifyOneAdWatched) {
NotifyMan.instance().sendEvent(VididinEvents.EVENT_FINISHED_ONE_AD, NotifyMan.NotifyData(1))
}
finish()
}
private fun stateCounter() {
mCountDownTimer = object : CountDownTimer(50* 1000, 1000) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = millisUntilFinished / 1000
//binding.tvAdCounter.text = "${secondsRemaining}"
}
override fun onFinish() {
}
}
mCountDownTimer.start()
}
override fun readIntent(intent: Intent) {
super.readIntent(intent)
mWatchType = intent.getIntExtra(KEY_TASK_TYPE, 0)
mExtraJsonStr = intent.getStringExtra(KEY_TASK_DATA)
}
override fun onDestroy() {
super.onDestroy()
mCountDownTimer.cancel()
NotifyMan.instance().sendEvent(VididinEvents.AD_ACT_DESTROY, null)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NotifyMan.instance().sendEvent(VididinEvents.AD_ACT_SHOWING, null)
}
override fun ViewBinding.initObservers() {
//TODO("Not yet implemented")
}
override fun onTabIsDarkFont(isDarkFont: Boolean) {
//TODO("Not yet implemented")
}
private fun showVideoAd() {
if (TestingManager.instance().isRewardAdDisable()) {
lifecycleScope.launch {
delay(2000)
mRewardedDollarNum = 0.02
notifyAdWatchFinish()
}
} else {
lifecycleScope.launch {
binding.root.postDelayed({
if (!mIsLoadSuccess) {
handleLoadFailed()
}
}, 3000)
try {
when(AdShowExt.showRewardedVideoAd(this@WatchAdActivity,
VidiStatisticHelper.getShowFromStr(mWatchType), { rewardedData ->
mRewardedDollarNum = rewardedData.rewardNum
}, {
notifyAdWatchFinish()
}, {
mIsLoadSuccess = true
})) {
is AdResult.Success -> {
mIsLoadSuccess = true
}
is AdResult.Failure -> {
handleLoadFailed()
}
AdResult.Loading -> {
val temp = 111
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private fun handleLoadFailed() {
AndroidUtil.showToast(R.string.ad_load_fail)
finish()
}
companion object {
private val KEY_TASK_TYPE = "KEY_TASK_TYPE"
private val KEY_TASK_DATA = "KEY_TASK_DATA"
internal fun startActivity(activity: Activity, taskType: Int, taskDataJson: String?) {
val intent = Intent(activity.applicationContext, WatchAdActivity::class.java)
intent.putExtra(KEY_TASK_TYPE, taskType)
intent.putExtra(KEY_TASK_DATA, taskDataJson)
activity.startActivity(intent)
}
}
}

View File

@ -4,59 +4,118 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat import androidx.core.view.isVisible
import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.Lifecycle
import androidx.core.view.updatePadding import androidx.lifecycle.lifecycleScope
import com.ama.core.architecture.appBase.AppViewsActivity import androidx.lifecycle.repeatOnLifecycle
import com.gamedog.vididin.R import androidx.recyclerview.widget.LinearLayoutManager
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.ama.core.architecture.util.CommonItemDecoration
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.ZeroBuyResp
import com.gamedog.vididin.features.zero.ZeroBuyViewModel
import com.gamedog.vididin.features.zero.ZeroRecordAdapter
import com.viddin.videos.free.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.manager.ZeroManager
import com.gamedog.vididin.netbase.Result
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityWinRecordBinding as ViewBinding import com.viddin.videos.free.databinding.ActivityWinRecordBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel
@AndroidEntryPoint @AndroidEntryPoint
class WinRecordsActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class WinRecordsActivity : AppViewsEmptyViewModelActivity<ViewBinding>(), OnTabStyleListener {
private val viewModel: ZeroBuyViewModel by viewModels()
private lateinit var mAdapter: ZeroRecordAdapter
override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
with(binding) { with(binding) {
titlebar.setBackIconColor(R.color.black) titlebar.setBackIconColor(R.color.black)
titlebar.setTitleText(R.string.lottery_record, R.color.black) titlebar.setTitleText(R.string.lottery_record, R.color.black)
with(recyclerView) {
mAdapter = ZeroRecordAdapter({
ZeroManager.instance().startWithdrawProcess(this@WinRecordsActivity, it)
})
adapter = mAdapter
layoutManager = LinearLayoutManager(this@WinRecordsActivity, LinearLayoutManager.VERTICAL, false)
addItemDecoration(
CommonItemDecoration.create(horizontalSpace = 0, verticalSpace = 30)
)
}
} }
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(contentRoot)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
//TODO("Not yet implemented")
registerEvents({ data->
when (data?.mEventType) {
VididinEvents.EVENT_ZERO_WITHDRAW_LIST_CHANGED -> {
mAdapter.notifyDataSetChanged()
}
}
}, VididinEvents.EVENT_ZERO_WITHDRAW_LIST_CHANGED,)
requestData()
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
//TODO("Not yet implemented") //TODO("Not yet implemented")
} }
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
//TODO("Not yet implemented")
}
override fun onTabIsDarkFont(isDarkFont: Boolean) { override fun onTabIsDarkFont(isDarkFont: Boolean) {
//TODO("Not yet implemented") //TODO("Not yet implemented")
} }
private fun requestData() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.ZeroBuyListData.collect { result ->
when (result) {
is Result.Loading -> { showLoading(false) }
is Result.Success -> {
hideLoading()
updateUIs(result.data)
}
is Result.Error -> {
hideLoading()
}
}
}
}
}
viewModel.requestZeroBuyInfo()
}
private fun updateUIs(data: ZeroBuyResp) {
val dataList = data.finished_purchases
if (dataList.isNullOrEmpty()) {
binding.tvNoDataHint.isVisible = true
binding.recyclerView.isVisible = false
} else {
binding.tvNoDataHint.isVisible = false
binding.recyclerView.isVisible = true
mAdapter.submitList(dataList)
}
}
companion object { companion object {
internal fun startActivity(activity: Activity) { internal fun startActivity(activity: Activity) {

View File

@ -48,4 +48,12 @@ object BankUtil {
val remainder = sum % 11 val remainder = sum % 11
return if (remainder < 2) 0 else 11 - remainder return if (remainder < 2) 0 else 11 - remainder
} }
private fun executeWithDraw() {
}
} }

View File

@ -0,0 +1,9 @@
package com.gamedog.vididin.features.withdraw
import android.app.Activity
class DefaultWithdrawSubRouter: WithdrawSubRouter {
override fun startActivity(activity: Activity, withdrawType: Int) {
WithDrawSubActivity.Companion.startActivity(activity, withdrawType)
}
}

View File

@ -3,93 +3,110 @@ package com.gamedog.vididin.features.withdraw
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.core.graphics.toColorInt
import com.ama.core.architecture.appBase.AppViewsActivity import androidx.core.view.isVisible
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.ama.core.architecture.highlightpro.HighlightPro
import com.ama.core.architecture.highlightpro.parameter.Constraints
import com.ama.core.architecture.highlightpro.parameter.HighlightParameter
import com.ama.core.architecture.highlightpro.parameter.MarginOffset
import com.ama.core.architecture.highlightpro.shape.RectShape
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.ResUtil.dp
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.vididin.R import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.viddin.videos.free.R
import com.gamedog.vididin.VididinEvents import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.Account import com.gamedog.vididin.beans.RecordCash
import com.gamedog.vididin.beans.WatchAdNotifyBean
import com.gamedog.vididin.core.login.login.AccountManager import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawBindBankDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawFailDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawInfoConfirmDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawSuccessDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawWatchAdDialog
import com.gamedog.vididin.features.withdraw.widget.WithDrawItemView import com.gamedog.vididin.features.withdraw.widget.WithDrawItemView
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.manager.GuideManager
import com.gamedog.vididin.manager.TaskManager
import com.gamedog.vididin.manager.WithdrawItem
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.STATE_COULD_WITHDRAW
import com.gamedog.vididin.manager.WithdrawManager.Companion.STATE_WITHDRAW_SUCCESS
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_FAIL
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_SUCCESS
import com.gamedog.vididin.router.Router import com.gamedog.vididin.router.Router
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import com.viddin.videos.free.databinding.ActivityWithdrawBinding as ViewBinding
import com.gamedog.vididin.databinding.ActivityWithdrawBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel
@AndroidEntryPoint @AndroidEntryPoint
class WithDrawActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class WithDrawActivity : AppViewsEmptyViewModelActivity<ViewBinding>() {
override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
private val mItemViewList: MutableList<WithDrawItemView> = mutableListOf() private val mItemViewList: MutableList<WithDrawItemView> = mutableListOf()
private var mCurSelectedIndex: Int = 0
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
setImmerseRootView(contentRoot) setImmerseRootView(contentRoot)
} }
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
titlebar.setTitleText(R.string.sacar)
mItemViewList.add(withdraw01) mItemViewList.add(withdraw01)
mItemViewList.add(withdraw1)
mItemViewList.add(withdraw10) mItemViewList.add(withdraw10)
mItemViewList.add(withdraw20) mItemViewList.add(withdraw20)
mItemViewList.add(withdraw50) mItemViewList.add(withdraw50)
mItemViewList.add(withdraw100) mItemViewList.add(withdraw100)
mItemViewList.add(withdraw300) mItemViewList.add(withdraw300)
withdraw01.setNumAndAction(0, 0.1F, withdraw01.setNumAndAction(0, 0.1,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdraw10.setNumAndAction(1, 10F, withdraw1.setNumAndAction(1, 1.0,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdraw20.setNumAndAction(2, 20F, withdraw10.setNumAndAction(2, 10.0,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdraw50.setNumAndAction(3, 50F, withdraw20.setNumAndAction(3, 20.0,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdraw100.setNumAndAction(4, 100F, withdraw50.setNumAndAction(4, 50.0,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdraw300.setNumAndAction(5, 300F, withdraw100.setNumAndAction(5, 100.0,
{ itemIndex-> { itemIndex->
updateUIItemSelectStates(itemIndex) handleGotoWithdraw(itemIndex)
}) })
withdrawPix2.setIconAndText(R.mipmap.pix2, R.string.pix2, { withdraw300.setNumAndAction(6, 300.0,
{ itemIndex->
handleGotoWithdraw(itemIndex)
}) })
withdrawPix2.setIconAndText(R.mipmap.pix2_big, R.string.pix2, {
WithdrawBindBankDialog(this@WithDrawActivity, null).setWithDrawCashNum(0.0).show()
})
withdrawPix2.setSelectedState(true) withdrawPix2.setSelectedState(true)
updateUIItemSelectStates(0)
setOnClickBatch(tvSacar, withdrawRecord) { setOnClickBatch(withdrawRecord) {
when(this) { when(this) {
tvSacar -> {
val hasBindBank = AccountManager.hasValidBankInfo()
if (!hasBindBank) {
WithdrawBindBankDialog(this@WithDrawActivity).show()
}
}
withdrawRecord -> { withdrawRecord -> {
Router.WithdrawRecord.startActivity(this@WithDrawActivity) Router.WithdrawRecord.startActivity(this@WithDrawActivity)
} }
@ -97,35 +114,207 @@ class WithDrawActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), On
} }
updateUICashTotal() updateUICashTotal()
// TaskManager.instance().newbieFirstWithdrawStatus().getStatusBean().hasWithdrawed
if (WithdrawManager.instance().getItemState(0, 0) == STATE_WITHDRAW_SUCCESS
|| TaskManager.instance().newbieFirstWithdrawStatus().smallCashHasWithdrawed()) {
withdraw01.isVisible = false
} }
private fun updateUIItemSelectStates(itemIndex: Int) { StatisticUtil.reportEvents(StatisticUtil.KEY_Withdrawal_Show)
mCurSelectedIndex = itemIndex
mItemViewList.forEachIndexed { index, view ->
view.setSelectedState(index == mCurSelectedIndex)
} }
private fun handleGotoWithdraw(itemIndex: Int) {
val cashNum = mItemViewList.get(itemIndex).getCashNum()
if (cashNum >= 1.0) {
WithdrawManager.instance().setItemStarted(itemIndex)
gotoWithdrawSubActivity(itemIndex)
} else {
val hasBindBank = AccountManager.hasValidBankInfo()
if (!hasBindBank) {
WithdrawBindBankDialog(this@WithDrawActivity, ::startRealWithdraw ).setWithDrawCashNum(cashNum).show()
} else {
if (WithdrawManager.instance().getItemState(0, 0) == STATE_COULD_WITHDRAW) {
WithdrawInfoConfirmDialog(this@WithDrawActivity, ::startRealWithdraw).setWithDrawCashNum(cashNum).show()
} else {
WithdrawWatchAdDialog(this@WithDrawActivity, cashNum, ::startRealWithdraw).show()
}
}
}
StatisticUtil.reportEvents(StatisticUtil.KEY_Withdrawal_finsh, mapOf("Withdrawal_Position" to cashNum))
}
private fun startRealWithdraw(cashNum: Double) {
// payCashNum: Double, payItemId: Int, paySubItemId: Int, payItemLoopIndex: Int
WithdrawManager.instance().startWithdrawReal(cashNum, 0, 0, 1)
WithdrawManager.instance().setItemStarted(0)
} }
private fun updateUICashTotal() { private fun updateUICashTotal() {
binding.tvCashTotal.text = AccountManager.getCash().toString() binding.tvCashTotal.text = String.format("%.2f", AccountManager.getCash())
binding.tvAllCashHasWithdrawed.text = buildString {
append(ResUtil.getString(R.string.cash))
append(" ")
append(WithdrawManager.instance().getHasWithdrawSuccessCashCount())
} }
}
private fun updateItemListUI() {
mItemViewList.forEach {
it.updateProgressAndButUI()
}
if (WithdrawManager.instance().getItemState(0, 0) == STATE_WITHDRAW_SUCCESS
|| TaskManager.instance().newbieFirstWithdrawStatus().smallCashHasWithdrawed()) {
binding.withdraw01.isVisible = false
}
}
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
registerEvents({ data-> registerEvents({ data->
when (data?.mEventType) {
VididinEvents.Event_Account_Cash_Changed -> {
updateUICashTotal() updateUICashTotal()
}, VididinEvents.Event_Account_Cash_Changed)
} }
VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_SMALL -> {
val adNotifyBean = data.mData as WatchAdNotifyBean<Double>
WithdrawManager.instance().addAdEarnForSubBean(0, 0,
adNotifyBean.earnMoneyNum * VidiConst.WITHDRAW_REWARD_AD_REVENUE_PERCENT)
}
VididinEvents.EVENT_WITHDRAW_RESULT_UPDATED -> {
try {
val record = data.mData as RecordCash
if (record.withdrawItemIndex == 0) {
showTransactionResultDialog(record)
}
updateUICashTotal()
mItemViewList[record.withdrawItemIndex].updateProgressAndButUI()
} catch (e: Exception) {
e.printStackTrace()
}
}
VididinEvents.EVENT_WITHDRAW_ITEM_LIST_CHANGED -> {
updateItemListUI()
}
VididinEvents.EVENT_BANK_INFO_CHANGED -> {
withdrawPix2.updateBankAccountInfo()
}
VididinEvents.EVENT_WITHDRAW_SUB_ITEM_PROGRESS_UPDATED -> {
updateItemListUI()
}
VididinEvents.EVENT_WITHDRAW_SMALL_AD_FINISHED -> {
handleGotoWithdraw(0)
}
}
}, VididinEvents.Event_Account_Cash_Changed,
VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_SMALL,
VididinEvents.EVENT_WITHDRAW_RESULT_UPDATED,
VididinEvents.EVENT_WITHDRAW_ITEM_LIST_CHANGED,
VididinEvents.EVENT_BANK_INFO_CHANGED,
VididinEvents.EVENT_WITHDRAW_SUB_ITEM_PROGRESS_UPDATED,
VididinEvents.EVENT_WITHDRAW_SMALL_AD_FINISHED)
readTransactionsAndShowResult()
if (needShowGuide()) {
binding.tvCashTotal.postDelayed({
showGuide()
}, 5)
}
}
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
//TODO("Not yet implemented") //TODO("Not yet implemented")
} }
override fun ViewBinding.onUiStateCollect(uiState: UiState) { private fun showSuccessDialog(cashNum: Double) {
//TODO("Not yet implemented") WithdrawSuccessDialog(this@WithDrawActivity, cashNum).show()
} }
override fun onTabIsDarkFont(isDarkFont: Boolean) { private fun showFailDialog(failHintRes: Int) {
//TODO("Not yet implemented") WithdrawFailDialog(this@WithDrawActivity, failHintRes).show()
}
private fun gotoWithdrawSubActivity(selectedIndex: Int) {
Router.WithdrawSub.startActivity(this, selectedIndex)
}
// ------------------------ new added -------------------------//
private fun readTransactionsAndShowResult() {
val recordList = WithdrawManager.instance().getClonedRecordList()
recordList.forEach {
showTransactionResultDialog(it)
}
}
private fun showTransactionResultDialog(record: RecordCash) {
if (!record.hasShowResultDialog && record.withdrawState != TRANSACTION_STATE_ONGOING) {
WithdrawManager.instance().updateRecordHasNotifyState(record.uuid)
when (record.withdrawState) {
TRANSACTION_STATE_SUCCESS -> {
showSuccessDialog(record.amountNum)
}
TRANSACTION_STATE_FAIL -> {
showFailDialog(WithdrawManager.instance().getFailHintStrRes(record.withdrawFailType))
}
}
}
}
private fun needShowGuide(): Boolean {
return GuideManager.instance().getCurGuideIndex() == VidiConst.GUIDE_INDEX_CASH_GOLD
}
private fun saveGuideState() {
GuideManager.instance().setGuideIndex(VidiConst.GUIDE_INDEX_WITHDRAW)
}
override fun onDestroy() {
super.onDestroy()
}
private fun showGuide() {
HighlightPro.with(this@WithDrawActivity)
.setHighlightParameter {
HighlightParameter.Builder()
.setHighlightView(mItemViewList.get(0), {
})
.setTipsViewId(R.layout.guide_step_withdraw)
.setHighlightShape(RectShape(10.dp, 10.dp, 10.dp))
.setHighlightHorizontalPadding(0.dp)
.setConstraints(Constraints.TopToBottomOfHighlight + Constraints.EndToEndOfHighlight)
.setMarginOffset(MarginOffset(top = -40.dp.toInt(), end = 0.dp.toInt()))
.build()
}
.setBackgroundColor("#cc000000".toColorInt())
.setOnShowCallback { index ->
}
.setOnDismissCallback {
saveGuideState()
handleGotoWithdraw(0)
}
.interceptBackPressed(true)
.show()
StatisticUtil.reportEvents(StatisticUtil.KEY_Guide, mapOf("Guide" to 3))
} }

View File

@ -0,0 +1,276 @@
package com.gamedog.vididin.features.withdraw
import android.app.Activity
import android.content.Intent
import android.text.Spannable
import android.text.SpannableString
import android.text.method.ScrollingMovementMethod
import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.CommonItemDecoration
import com.ama.core.architecture.util.DateUtil
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.RecordCash
import com.gamedog.vididin.beans.WatchAdNotifyBean
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawBindBankDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawFailDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawInfoConfirmDialog
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawSuccessDialog
import com.gamedog.vididin.manager.WithdrawItem
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_FAIL
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_SUCCESS
import com.gamedog.vididin.router.Router
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue
import com.viddin.videos.free.databinding.ActivityWithdrawSubBinding as ViewBinding
@AndroidEntryPoint
class WithDrawSubActivity : AppViewsEmptyViewModelActivity<ViewBinding>() {
private lateinit var mCurItem: WithdrawItem
private var mSelectingIndex: Int = 0
private var mType: Int = 0
private val mAdapter: WithdrawSubAdapter by lazy { WithdrawSubAdapter( { itemIndex ->
handleSubItemClicked(itemIndex)
}) }
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initWindowInsets() {
setImmerseRootView(contentRoot)
}
override fun ViewBinding.initViews() {
mType = intent.getIntExtra(EXTRA_TYPE, 0)
titlebar.setTitleText(R.string.title_withdraw_sub)
titlebar.setTitleTextSize(17F)
recyclerView.layoutManager = LinearLayoutManager(this@WithDrawSubActivity, LinearLayoutManager.HORIZONTAL, false)
recyclerView.adapter = mAdapter
recyclerView.addItemDecoration(CommonItemDecoration.create(18, 0, false))
tvHint.movementMethod = ScrollingMovementMethod.getInstance()
tvHint.isSelected = true
val foreColorSpan = ForegroundColorSpan(ResUtil.getColor(R.color.green_39))
val ssb = SpannableString(tvTopHint.text).apply {
setSpan(foreColorSpan, 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
tvTopHint.text = ssb
setOnClickBatch(flAction) {
when(this) {
flAction -> {
when (mCurItem.subItemList[mSelectingIndex].withdrawState) {
WithdrawManager.STATE_NEED_WATCH_AD -> {
gotoWatchAd()
sendClickStatistic()
}
WithdrawManager.STATE_COULD_WITHDRAW -> {
tryRequestWithdraw()
}
}
}
}
}
}
private fun tryRequestWithdraw() {
val subBean = mCurItem.subItemList[mSelectingIndex]
if (AccountManager.isBankAccountExist()) {
WithdrawInfoConfirmDialog(this@WithDrawSubActivity, { cashNum -> startRealWithdraw(cashNum) }).setWithDrawCashNum(subBean.cashTotal).show()
} else {
WithdrawBindBankDialog(this@WithDrawSubActivity, { cashNum -> startRealWithdraw(cashNum) }).setWithDrawCashNum(subBean.cashTotal).show()
}
}
private fun startRealWithdraw(cashNum: Double) {
val withdrawItemIndex = mCurItem.index
val withdrawSubItemIndex = mCurItem.subItemList[mSelectingIndex].dayIndex
WithdrawManager.instance().startWithdrawReal(cashNum, withdrawItemIndex, withdrawSubItemIndex, mCurItem.loopIndex)
WithdrawManager.instance().setItemStarted(0)
}
private fun showSuccessDialog(cashNum: Double) {
WithdrawSuccessDialog(this, cashNum).show()
}
private fun showFailDialog(errorHintRes: Int) {
WithdrawFailDialog(this, errorHintRes).show()
}
private fun handleSubItemClicked(itemIndex: Int) {
val mMaxDayIndex = DateUtil.getDaysPassed(mCurItem.startMs)
if (itemIndex >= 0 && itemIndex <= mMaxDayIndex) {
mSelectingIndex = itemIndex
updateUI()
}
}
private fun gotoWatchAd() {
Router.WatchAd.startActivity(this, VidiConst.WATCH_AD_FOR_WITHDRAW_BIG, AndroidUtil.object2Json(mCurItem))
}
override fun ViewBinding.initListeners() {
registerEvents({ data->
when (data?.mEventType) {
VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_BIG -> {
handleAdWatched(data.mData as WatchAdNotifyBean<WithdrawItem>)
}
VididinEvents.EVENT_WITHDRAW_SUB_ITEM_PROGRESS_UPDATED -> {
if ((data.mData as Int) == mSelectingIndex) {
updateProgressUI()
}
}
VididinEvents.EVENT_WITHDRAW_SELECTED_SUB_ITEM_CHANGED -> {
updateUI()
}
VididinEvents.EVENT_WITHDRAW_ITEM_LIST_CHANGED -> {
updateUI()
}
VididinEvents.EVENT_WITHDRAW_RESULT_UPDATED -> {
try {
val record = data.mData as RecordCash
if (record.withdrawItemIndex > 0) {
showTransactionResultDialog(record)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}, VididinEvents.EVENT_AD_WATCHED_FOR_WITHDRAW_BIG,
VididinEvents.EVENT_WITHDRAW_SUB_ITEM_PROGRESS_UPDATED,
VididinEvents.EVENT_WITHDRAW_SELECTED_SUB_ITEM_CHANGED,
VididinEvents.EVENT_WITHDRAW_RESULT_UPDATED,
VididinEvents.EVENT_WITHDRAW_ITEM_LIST_CHANGED)
mCurItem = WithdrawManager.instance().getItem(mType)
if (mCurItem.startMs <= 0L) {
WithdrawManager.instance().startItem(mCurItem)
}
mSelectingIndex = DateUtil.getDaysPassed(mCurItem.startMs)
updateUI()
}
private fun showTransactionResultDialog(record: RecordCash) {
if (!record.hasShowResultDialog && record.withdrawState != TRANSACTION_STATE_ONGOING) {
WithdrawManager.instance().updateRecordHasNotifyState(record.uuid)
when (record.withdrawState) {
TRANSACTION_STATE_SUCCESS -> {
showSuccessDialog(record.amountNum)
}
TRANSACTION_STATE_FAIL -> {
showFailDialog(WithdrawManager.instance().getFailHintStrRes(record.withdrawFailType))
}
}
}
}
private fun handleAdWatched(adNotifyBean: WatchAdNotifyBean<WithdrawItem>) {
val withdrawItemBean = adNotifyBean.extraData
if (WithdrawManager.instance().addAdEarnForSubBean(withdrawItemBean.index,
mSelectingIndex, adNotifyBean.earnMoneyNum * VidiConst.WITHDRAW_REWARD_AD_REVENUE_PERCENT)) {
updateUI()
}
}
private fun updateUI() {
with(binding) {
mAdapter.mSelectedSubIndex = mSelectingIndex
mAdapter.submitList(mCurItem.subItemList)
mAdapter.notifyDataSetChanged()
recyclerView.scrollToPosition(mSelectingIndex)
tvCashTotal.text = mCurItem.totalCashNum.toString()
progressBar.enableTouch(false)
progressBar.setBarColor(forColor = R.color.green_ce)
updateProgressUI()
}
}
private fun updateProgressUI() {
with(binding) {
val subBean = mCurItem.subItemList[mSelectingIndex]
val curProgress = subBean.currentAdProgress
progressBar.setProgress(curProgress)
tvProgress.text = "${"%.2f".format(curProgress) }%"
ivAction.isVisible = curProgress < 100
if (curProgress < 100) {
tvAction.setText(R.string.withdraw_cash_out)
flAction.isClickable = true
flAction.alpha = 1F
sendShowStatistic()
} else {
var actionText = R.string.withdraw_cash_out
when(subBean.withdrawState) {
WithdrawManager.STATE_COULD_WITHDRAW -> {
actionText = R.string.withdraw_cash_out
flAction.isClickable = true
flAction.alpha = 1F
}
WithdrawManager.STATE_WITHDRAWING -> {
actionText = R.string.pending
flAction.isClickable = false
flAction.alpha = 0.6F
}
WithdrawManager.STATE_WITHDRAW_SUCCESS -> {
actionText = R.string.withdraw_success
flAction.isClickable = false
flAction.alpha = 0.6F
}
}
tvAction.setText(actionText)
}
}
}
private fun sendShowStatistic() {
StatisticUtil.reportEvents(StatisticUtil.KEY_RV_Button_Show, mapOf("Position" to "RV_Accelerate2"))
}
private fun sendClickStatistic() {
StatisticUtil.reportEvents(StatisticUtil.KEY_RV_Button_Click, mapOf("Position" to "RV_Accelerate2"))
}
override fun ViewBinding.initObservers() {
}
companion object {
const val EXTRA_TYPE = "EXTRA_TYPE"
internal fun startActivity(activity: Activity, withdrawType: Int) {
activity.startActivity(Intent(activity.applicationContext,
WithDrawSubActivity::class.java).apply { putExtra(EXTRA_TYPE, withdrawType) })
}
}
}

View File

@ -1,103 +0,0 @@
package com.gamedog.vididin.features.withdraw
import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import androidx.core.view.isVisible
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.R
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.databinding.DialogWithdrawBindingBankBinding as ViewBinding
import com.gamedog.vididin.router.Router
class WithdrawBindBankDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setBottom()
setMaskValue(0.9f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
tvConfirm -> {
saveBankAccount(mBinding.tvCpfEdit.text.toString().trim())
}
}
}
tvCpfEdit.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
checkBankAccountValidation(s.toString())
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(
s: CharSequence?,
start: Int,
before: Int,
count: Int
) {
}
})
}
checkBankAccountValidation("")
}
private fun saveBankAccount(bankAccount: String) {
AccountManager.saveBankAccount(bankAccount)
}
private fun checkBankAccountValidation(bankAccount: String) {
// TODO - forTesting- contain "B"
if (BankUtil.isValidCpf(bankAccount) || bankAccount.contains("B")) {
mBinding.ivState.isVisible = true
mBinding.ivState.setImageResource(R.mipmap.icon_success)
mBinding.tvConfirm.alpha = 1F
mBinding.tvConfirm.isClickable = true
} else {
mBinding.ivState.isVisible = !bankAccount.isEmpty()
mBinding.ivState.setImageResource(R.mipmap.icon_fail)
mBinding.tvConfirm.alpha = 0.3F
mBinding.tvConfirm.isClickable = false
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
}
}

View File

@ -1,42 +0,0 @@
package com.gamedog.vididin.features.withdraw
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogWithdrawBindingBankFinishBinding as ViewBinding
import com.gamedog.vididin.router.Router
class WithdrawBindBankFinishDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
tvConfirm, ivClose -> {
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
}

View File

@ -1,42 +0,0 @@
package com.gamedog.vididin.features.withdraw
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogWithdrawFailBinding as ViewBinding
import com.gamedog.vididin.router.Router
class WithdrawFailDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
tvConfirm, ivClose -> {
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
}

View File

@ -0,0 +1,67 @@
package com.gamedog.vididin.features.withdraw
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.manager.WithdrawSubItem
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.LayoutItemWithdrawSubBinding as ViewBinding
class WithdrawSubAdapter(private val selectCallback: (index: Int)->Unit) : ListAdapter<WithdrawSubItem, WithdrawSubAdapter.ViewHolder>(DiffCallback()) {
var mSelectedSubIndex: Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding,)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.rootView.setOnClickListener {
selectCallback.invoke(position)
}
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: WithdrawSubItem) {
with(binding) {
tvTitle.text = buildString {
append(ResUtil.getString(R.string.cash))
append(item.cashTotal)
}
tvDay.text = buildString {
append(ResUtil.getString(R.string.day))
append(" ")
append(item.dayIndex + 1)
}
if (item.dayIndex == mSelectedSubIndex) {
root.setBackgroundResource(R.drawable.bg_withdraw_sub_selected)
root.alpha = 1F
ivLefttopChecked.isVisible = true
} else {
root.setBackgroundResource(R.drawable.bg_withdraw_sub_unselected)
root.alpha = 0.7F
ivLefttopChecked.isVisible = false
}
}
}
}
class DiffCallback : DiffUtil.ItemCallback<WithdrawSubItem>() {
override fun areItemsTheSame(oldItem: WithdrawSubItem, newItem: WithdrawSubItem): Boolean {
return oldItem.dayIndex == newItem.dayIndex
}
override fun areContentsTheSame(oldItem: WithdrawSubItem, newItem: WithdrawSubItem): Boolean {
return newItem == oldItem
}
}
}

View File

@ -0,0 +1,7 @@
package com.gamedog.vididin.features.withdraw
import android.app.Activity
interface WithdrawSubRouter {
fun startActivity(activity: Activity, withdrawType: Int)
}

View File

@ -1,42 +0,0 @@
package com.gamedog.vididin.features.withdraw
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogWithdrawSuccessBinding as ViewBinding
import com.gamedog.vididin.router.Router
class WithdrawSuccessDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
tvConfirm, ivClose -> {
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
}

View File

@ -0,0 +1,115 @@
package com.gamedog.vididin.features.withdraw
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DeviceUtil
import com.ama.core.architecture.util.MD5Util
import com.ama.core.architecture.util.NetUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.beans.req.PayInitReq
import com.gamedog.vididin.beans.req.PayoutCheckReq
import com.gamedog.vididin.beans.req.PayoutReq
import com.gamedog.vididin.beans.resp.PayInit
import com.gamedog.vididin.beans.resp.PayoutCheckData
import com.gamedog.vididin.beans.resp.PayoutData
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.netbase.NetworkUtil
import com.gamedog.vididin.netbase.Result
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class WithdrawViewModel : ViewModel() {
private val _InitData = MutableStateFlow<Result<PayInit>>(Result.Loading)
val InitData: StateFlow<Result<PayInit>> = _InitData.asStateFlow()
private val _PayoutResult = MutableStateFlow<Result<PayoutData?>>(Result.Loading)
val PayoutResult: StateFlow<Result<PayoutData?>> = _PayoutResult.asStateFlow()
private val _CheckResult = MutableStateFlow<Result<PayoutCheckData?>>(Result.Loading)
val CheckResult: StateFlow<Result<PayoutCheckData?>> = _CheckResult.asStateFlow()
fun withdrawInit() {
viewModelScope.launch {
val requestParam = PayInitReq().applyInitFields()
_InitData.value = Result.Loading
_InitData.value = NetworkUtil.callApi {
NetworkUtil.apiservice().withdrawInit(requestParam)
}
}
}
fun withdrawPayout(initUUID: String, payItemId: Int, payCashNum: Double) {
viewModelScope.launch {
val requestParam = PayoutReq().applyInitFields().apply {
val bankAccount = AccountManager.getAccount().bankInfo?.bankAccount
val accountType = "CPF"
account = bankAccount
item_id = payItemId
amount = payCashNum.toString()
additional_remark = "communnyboneycashmoneyrewardfastrealgame"
uuid = initUUID
account_type = accountType
document_type = accountType
document_id = bankAccount
name = "CapyBucks"
clientName = AndroidUtil.getPackageId()
dataAdjust.gps_adid = "gaid"
dataAdjust.android_id = "androidid"
dataAdjust.adid = "adid"
dataAdjust.user_agent = "GetUerAgent"
dataAdjust.price = amount
dataAdjust.currency = "USD"
dataShuShu.gps_gaid = "gaid"
dataShuShu.android_id = "androidid"
dataShuShu.adid = "adid"
dataShuShu.user_agent = "GetUerAgent"
dataShuShu.price = amount
dataShuShu.currency = "USD"
dataShuShu.payment_method = "Pix"
dataShuShu.payment_type = accountType
dataShuShu.payment_number = account
dataShuShu.iap_name = "100br"
dataShuShu.gamecoin_number = "100"
dataShuShu.gamecoin_type = "gold"
dataShuShu.ss_account_id = "GetSSAccountId"
dataShuShu.ss_distinct_id = "GetSSDistinctId"
dataShuShu.ss_super_properties = "GetSSSuper Properties"
}
_PayoutResult.value = Result.Loading
_PayoutResult.value = NetworkUtil.callApi {
NetworkUtil.apiservice().withdrawPayout(requestParam)
}
}
}
fun withdrawCheck(recordNo: String) {
viewModelScope.launch {
val requestParam = PayoutCheckReq().applyInitFields().apply {
record_no = recordNo
}
_CheckResult.value = Result.Loading
_CheckResult.value = NetworkUtil.callApi {
NetworkUtil.apiservice().withdrawCheck(requestParam)
}
}
}
private fun <T : PayInitReq> T.applyInitFields(): T {
return WithdrawManager.instance().applyInitFields(this)
}
}

View File

@ -0,0 +1,144 @@
package com.gamedog.vididin.features.withdraw.dialogs
import android.app.Activity
import android.text.Editable
import android.text.TextWatcher
import androidx.core.view.isVisible
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.statisticreporter.StatisticUtil
import com.viddin.videos.free.R
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.features.withdraw.BankUtil
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.STATE_COULD_WITHDRAW
import com.gamedog.vididin.manager.WithdrawManager.Companion.STATE_NEED_WATCH_AD
import com.viddin.videos.free.databinding.DialogWithdrawBindingBankBinding as ViewBinding
class WithdrawBindBankDialog(activity: Activity, private val onConfirmedWithdraw: ((cashNum: Double)->Unit)?) : BindingDialog<ViewBinding>(activity, ViewBinding::inflate) {
private var mWithdrawCashNum: Double = 0.0
private var mWithdrawCashNumStr: String = ""
init {
build()
}
private fun build() {
with()
setBottom()
setMaskValue(0.9f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
tvConfirm -> {
saveBankAccount(mBinding.tvCpfEdit.text.toString().trim())
if (onConfirmedWithdraw != null) {
if (mWithdrawCashNum == 0.1 && WithdrawManager.instance().getItemState(0, 0) == STATE_NEED_WATCH_AD) {
WithdrawWatchAdDialog(mActivity, mWithdrawCashNum, onConfirmedWithdraw).show()
} else {
val dialogBuilder = WithdrawInfoConfirmDialog(mActivity, onConfirmedWithdraw)
if (mWithdrawCashNum > 0F) {
dialogBuilder.setWithDrawCashNum(mWithdrawCashNum)
} else {
dialogBuilder.setWithDrawCashNumStr(mWithdrawCashNumStr)
}
dialogBuilder.show()
}
}
dismiss()
}
}
}
tvCpfEdit.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
checkBankAccountValidation(s.toString())
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(
s: CharSequence?,
start: Int,
before: Int,
count: Int
) {
}
})
AccountManager.getAccount().bankInfo?.bankAccount.also { tvCpfEdit.setText(it) }
}
checkBankAccountValidation(mBinding.tvCpfEdit.text.toString())
}
private fun saveBankAccount(bankAccount: String) {
AccountManager.saveBankAccount(bankAccount)
StatisticUtil.reportEvents(StatisticUtil.KEY_Withdrawal_Info, mapOf("Info_Type" to "CPF", "Withdrawal_Account" to bankAccount))
}
private fun checkBankAccountValidation(bankAccount: String) {
if (BankUtil.isValidCpf(bankAccount) || (bankAccount.trim().length == 11)) {
mBinding.ivState.isVisible = true
mBinding.ivState.setImageResource(R.mipmap.icon_success)
mBinding.tvConfirm.alpha = 1F
mBinding.tvConfirm.isClickable = true
} else {
mBinding.ivState.isVisible = !bankAccount.isEmpty()
mBinding.ivState.setImageResource(R.mipmap.icon_fail)
mBinding.tvConfirm.alpha = 0.3F
mBinding.tvConfirm.isClickable = false
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
}
fun setWithDrawCashNum(withdrawNum: Double): WithdrawBindBankDialog {
mWithdrawCashNum = withdrawNum
if (mWithdrawCashNum == 0.0) {
mBinding.tvConfirm.text = ResUtil.getString(R.string.confirm)
}
return this
}
fun setWithDrawCashNumStr(withdrawNumStr: String): WithdrawBindBankDialog {
mWithdrawCashNumStr = withdrawNumStr
if (mWithdrawCashNum == 0.0) {
mBinding.tvConfirm.text = ResUtil.getString(R.string.confirm)
}
return this
}
}

View File

@ -0,0 +1,54 @@
package com.gamedog.vididin.features.withdraw.dialogs
import android.app.Activity
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.viddin.videos.free.databinding.DialogWithdrawFailBinding as ViewBinding
import com.gamedog.vididin.router.Router
class WithdrawFailDialog(context: Activity, private val errorHintRes: Int) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvActionFeedback, tvActionConfirm, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
tvActionFeedback -> {
gotoFeedback()
dismiss()
}
tvActionConfirm -> {
dismiss()
}
}
}
//tvReason.setText(errorHintRes)
}
}
private fun gotoFeedback() {
Router.Feedback.startActivity(mActivity)
}
}

View File

@ -0,0 +1,86 @@
package com.gamedog.vididin.features.withdraw.dialogs
import android.app.Activity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.statisticreporter.StatisticUtil
import com.viddin.videos.free.R
import com.gamedog.vididin.core.login.login.AccountManager
import com.viddin.videos.free.databinding.DialogWithdrawInfoConfirmBinding as ViewBinding
class WithdrawInfoConfirmDialog(context: Activity, private val onConfirmed: (cashNum: Double)->Unit) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
private var mWithdrawCashNum: Double = 0.0
private var mWithdrawCashNumStr: String = ""
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvActionAlter, tvActionApply, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
tvActionAlter -> {
val dialogBuilder = WithdrawBindBankDialog(activity = mActivity, onConfirmed)
if (!mWithdrawCashNumStr.isEmpty()) {
dialogBuilder.setWithDrawCashNumStr(mWithdrawCashNumStr).show()
} else {
dialogBuilder.setWithDrawCashNum(mWithdrawCashNum).show()
}
dismiss()
}
tvActionApply -> {
onConfirmed.invoke(mWithdrawCashNum)
StatisticUtil.reportEvents(StatisticUtil.KEY_Withdrawal_Apply,
mapOf("Withdrawal_Position" to mWithdrawCashNum,
"Withdrawal_Day" to 1))
dismiss()
}
}
}
}
}
fun setWithDrawCashNum(withdrawNum: Double): WithdrawInfoConfirmDialog {
mWithdrawCashNum = withdrawNum
mBinding.tvCashNum.text = buildString {
append(ResUtil.getString(R.string.cash))
append(" ")
append(mWithdrawCashNum)
}
mBinding.tvCpfAccount.text = AccountManager.getBankInfo()?.bankAccount
return this
}
fun setWithDrawCashNumStr(withdrawNumStr: String): WithdrawInfoConfirmDialog {
mWithdrawCashNumStr = withdrawNumStr
mBinding.tvCashNum.text = buildString {
append(mWithdrawCashNumStr)
}
mBinding.tvCpfAccount.text = AccountManager.getBankInfo()?.bankAccount
return this
}
}

View File

@ -0,0 +1,46 @@
package com.gamedog.vididin.features.withdraw.dialogs
import android.app.Activity
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.DialogWithdrawSuccessBinding as ViewBinding
class WithdrawSuccessDialog(context: Activity, private val mCashNum: Double = 0.0, private val cashNumStr: String = "") : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(flAction, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
flAction -> {
dismiss()
}
}
}
if (mCashNum > 0F) {
tvCashNum.text = ResUtil.getString(R.string.cash) + " " + mCashNum.toString()
} else {
tvCashNum.text = cashNumStr
}
}
}
}

View File

@ -0,0 +1,61 @@
package com.gamedog.vididin.features.withdraw.dialogs
import android.app.Activity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.router.Router
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.DialogWithdrawWatchAdBinding as ViewBinding
class WithdrawWatchAdDialog(context: Activity, private var mWithdrawCashNum: Double, private val onConfirmed: (cashNum: Double)->Unit) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
progressBar.setBarColor(R.color.blue_ba, R.color.blue_ff)
val subItem = WithdrawManager.instance().getItem(0).subItemList[0]
val progress = ((subItem.hasEarnMoneyByAd / subItem.cashTotal) * 100)
progressBar.setProgress(progress.toInt())
tvProgress.text = "%.2f".format(progress) + "%"
setOnClickBatch(flAction, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
flAction -> {
gotoWatchVideo()
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
Router.WatchAd.startActivity(mActivity, VidiConst.WATCH_AD_FOR_WITHDRAW_SMALL, AndroidUtil.object2Json(mWithdrawCashNum))
}
}

View File

@ -0,0 +1,75 @@
package com.gamedog.vididin.features.withdraw.widget
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import androidx.core.view.isVisible
import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.core.login.login.AccountManager
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.WithdrawItemBankViewBinding as ViewBinding
class WithDrawItemBankView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private var mItemIndex: Int = 0
private var mIsSelected = false
private var mBinding: ViewBinding
init {
mBinding = ViewBinding.inflate(LayoutInflater.from(context), this, true)
}
fun updateBankAccountInfo() {
with(mBinding) {
if (AccountManager.isBankAccountExist()) {
bankContainer.isVisible = true
tvBankHint.isVisible = false
AccountManager.getBankInfo()?.bankAccount?.let {
tvBankAccount.text = it
}
} else {
bankContainer.isVisible = false
tvBankHint.isVisible = true
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
updateBankAccountInfo()
}
/**
* For withdraw number in top area
*/
fun setAction(itemIndex: Int, clickAction: (Int)->Unit) {
mItemIndex = itemIndex
mBinding.root.setOnClickListener {
clickAction.invoke(mItemIndex)
}
}
/**
* For bank item in bottom area
*/
fun setIconAndText(iconRes: Int, textRes: Int, clickAction: ()->Unit) {
mBinding.tvWithdrawNum.text = ResUtil.getString(textRes)
mBinding.ivItemIcon.setImageResource(iconRes)
mBinding.root.setOnClickListener {
clickAction.invoke()
}
}
fun setSelectedState(isSelected: Boolean) {
mIsSelected = isSelected
mBinding.root.setBackgroundResource(if (mIsSelected) R.drawable.withdraw_item_bg_selected else R.drawable.withdraw_item_bg_unselected)
}
}

View File

@ -1,12 +1,18 @@
package com.gamedog.vididin.features.withdraw.widget package com.gamedog.vididin.features.withdraw.widget
import android.accounts.AccountManager
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import com.ama.core.architecture.util.ResUtil import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.R import com.ama.core.architecture.util.SpUtil
import com.gamedog.vididin.databinding.WithdrawItemViewBinding as ViewBinding import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.statisticreporter.adjust.SpHelper.Companion.KEY_USER_FROM_TYPE
import com.gamedog.vididin.manager.WithdrawManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.STATE_WITHDRAWING
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.WithdrawItemViewBinding as ViewBinding
class WithDrawItemView @JvmOverloads constructor( class WithDrawItemView @JvmOverloads constructor(
@ -15,8 +21,7 @@ class WithDrawItemView @JvmOverloads constructor(
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) { ) : LinearLayout(context, attrs, defStyleAttr) {
private var mItemIndex: Int = 0 private var mItemIndex: Int = 0
private var mIsSelected = false private var mCashNum: Double = 0.0
private var mCashNum: Float = 0F
private var mBinding: ViewBinding private var mBinding: ViewBinding
@ -28,30 +33,50 @@ class WithDrawItemView @JvmOverloads constructor(
/** /**
* For withdraw number in top area * For withdraw number in top area
*/ */
fun setNumAndAction(itemIndex: Int, cashNum: Float, clickAction: (Int)->Unit) { fun setNumAndAction(itemIndex: Int, cashNum: Double, clickAction: (Int)->Unit) {
mItemIndex = itemIndex mItemIndex = itemIndex
mCashNum = cashNum mCashNum = cashNum
mBinding.tvWithdrawNum.text = cashNum.toString() mBinding.tvWithdrawNum.text = ResUtil.getString(R.string.cash) + " " +
mBinding.root.setOnClickListener { if (cashNum.toString().endsWith(".0")) cashNum.toString().substring(0, cashNum.toString().indexOf(".0")) else cashNum.toString()
setOnClickBatch(mBinding.tvSacar) {
when (this) {
mBinding.tvSacar-> {
clickAction.invoke(mItemIndex) clickAction.invoke(mItemIndex)
} }
} }
/**
* For bank item in bottom area
*/
fun setIconAndText(iconRes: Int, textRes: Int, clickAction: ()->Unit) {
mBinding.tvWithdrawNum.text = ResUtil.getString(textRes)
mBinding.ivItemIcon.setImageResource(iconRes)
mBinding.root.setOnClickListener {
clickAction.invoke()
}
} }
fun setSelectedState(isSelected: Boolean) { updateProgressAndButUI()
mIsSelected = isSelected }
mBinding.root.setBackgroundResource(if (mIsSelected) R.drawable.withdraw_item_bg_selected else R.drawable.withdraw_item_bg_unselected)
fun getCashNum(): Double {
return mCashNum
}
fun updateProgressAndButUI() {
var itemProgress = WithdrawManager.instance().getItemProgress(mItemIndex) * 100
/*if (mItemIndex == 0 && SpUtil.instance().getInt(KEY_USER_FROM_TYPE) == 2 && itemProgress > 0) {
itemProgress = 100.0
}*/
with(mBinding) {
progressBar.setProgress(itemProgress.toInt())
tvProgress.text = String.format("%.2f", itemProgress) + ResUtil.getString(R.string.percent)
var is01Withdrawing = false
if (mItemIndex == 0) {
is01Withdrawing = WithdrawManager.instance().getItemState(mItemIndex, 0) == STATE_WITHDRAWING
}
// update ui
val canClickable: Boolean = itemProgress >= 100F && !is01Withdrawing
tvSacar.isClickable = canClickable
tvSacar.alpha = if (canClickable) 1F else 0.5F
}
} }

View File

@ -0,0 +1,53 @@
package com.gamedog.vididin.features.withdrawrecord
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.beans.RECORD_CASH_PLUS_GOLD_CONVERT
import com.gamedog.vididin.beans.RecordCashShow
import com.viddin.videos.free.R
import java.text.SimpleDateFormat
import com.viddin.videos.free.databinding.FragmentWithdrawRecordCashItemBinding as ViewBinding
class RecordCashRvAdapter : ListAdapter<RecordCashShow, RecordCashRvAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(data: RecordCashShow) {
binding.tvDate.text = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(data.dateMs)
binding.tvTitle.text = ResUtil.getString(data.title)
binding.ivType.setImageResource(data.iconRes)
binding.tvAmount.text = (if (data.amountNum < 0) "-" else "+") + ResUtil.getString(R.string.cash) + " " + String.format("%.2f", Math.abs(data.amountNum))
binding.tvAmount.setTextColor(ResUtil.getColor(data.textColor))
if (data.recordType == RECORD_CASH_PLUS_GOLD_CONVERT) {
binding.tvDescription.text = String.format(ResUtil.getString(data.description), Math.abs(data.amountNum *10 * VidiConst.PER_01CASH_COST_GOLD_NUM).toInt())
} else {
binding.tvDescription.text = ResUtil.getString(data.description)
}
}
}
class DiffCallback : DiffUtil.ItemCallback<RecordCashShow>() {
override fun areItemsTheSame(oldItem: RecordCashShow, newItem: RecordCashShow): Boolean {
return oldItem.uuid == newItem.uuid
}
override fun areContentsTheSame(oldItem: RecordCashShow, newItem: RecordCashShow): Boolean {
return oldItem.uuid == newItem.uuid
}
}
}

View File

@ -0,0 +1,23 @@
package com.gamedog.vididin.features.withdrawrecord
import com.ama.core.architecture.appBase.vm.AppViewModel
import com.gamedog.vididin.beans.RecordCash
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject
import com.gamedog.vididin.features.withdrawrecord.RecordCashUiState as UiState
@HiltViewModel
class RecordCashViewModel @Inject constructor() : AppViewModel<UiState>() {
override val uiStateInitialValue: UiState = UiState()
override val uiStateFlow: Flow<UiState> = flowOf()
}
data class RecordCashUiState(
val mRecordList: MutableList<RecordCash> = mutableListOf()
)

View File

@ -0,0 +1,48 @@
package com.gamedog.vididin.features.withdrawrecord
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.beans.RECORD_GOLD_MINUS_CONVERT_2_CASH
import com.gamedog.vididin.beans.RecordGoldShow
import java.text.SimpleDateFormat
import com.viddin.videos.free.databinding.FragmentWithdrawRecordGoldItemBinding as ViewBinding
class RecordGoldRvAdapter : ListAdapter<RecordGoldShow, RecordGoldRvAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(data: RecordGoldShow) {
binding.tvDate.text = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(data.dateMs)
binding.tvTitle.text = ResUtil.getString(data.title)
binding.tvAmount.text = (if(data.amountNum > 0) "+" else "") + data.amountNum.toString()
binding.ivType.setImageResource(data.iconRes)
if (data.recordType == RECORD_GOLD_MINUS_CONVERT_2_CASH) {
binding.tvDescription.text = String.format(ResUtil.getString(data.description), Math.abs(data.amountNum))
} else {
binding.tvDescription.text = ResUtil.getString(data.description)
}
}
}
class DiffCallback : DiffUtil.ItemCallback<RecordGoldShow>() {
override fun areItemsTheSame(oldItem: RecordGoldShow, newItem: RecordGoldShow): Boolean {
return oldItem.uuid == newItem.uuid
}
override fun areContentsTheSame(oldItem: RecordGoldShow, newItem: RecordGoldShow): Boolean {
return oldItem.uuid == newItem.uuid
}
}
}

View File

@ -0,0 +1,23 @@
package com.gamedog.vididin.features.withdrawrecord
import com.ama.core.architecture.appBase.vm.AppViewModel
import com.gamedog.vididin.beans.RecordGold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject
import com.gamedog.vididin.features.withdrawrecord.RecordGoldUiState as UiState
@HiltViewModel
class RecordGoldViewModel @Inject constructor() : AppViewModel<UiState>() {
override val uiStateInitialValue: UiState = UiState()
override val uiStateFlow: Flow<UiState> = flowOf()
}
data class RecordGoldUiState(
val mRecordList: MutableList<RecordGold> = mutableListOf()
)

View File

@ -0,0 +1,20 @@
package com.gamedog.vididin.features.withdrawrecord
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.gamedog.vididin.features.withdrawrecord.fragments.CashRecordFragment
import com.gamedog.vididin.features.withdrawrecord.fragments.GoldRecordFragment
class ViewPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> CashRecordFragment()
1 -> GoldRecordFragment()
else -> throw IllegalArgumentException("Invalid position: $position")
}
}
}

View File

@ -4,15 +4,16 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.gamedog.vididin.R import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.viddin.videos.free.R
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.ActivityWithdrawRecordBinding as ViewBinding import com.viddin.videos.free.databinding.ActivityWithdrawRecordBinding as ViewBinding
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
@ -26,19 +27,21 @@ class WithdrawRecordActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
with(binding) { with(binding) {
titlebar.setBackIconColor(R.color.black) setupViewPager()
titlebar.setTitleText(R.string.title_cash_record, R.color.black)
setOnClickBatch(ivBack) {
when (this) {
ivBack -> {
finish()
}
}
}
} }
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(binding.root)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
@ -58,6 +61,36 @@ class WithdrawRecordActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>
} }
private fun setupViewPager() {
val adapter = ViewPagerAdapter(this)
binding.viewPager.adapter = adapter
with (binding.tabLayout) {
addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
setTabTextColors(ResUtil.getColor(R.color.black),
ResUtil.getColor(if (selectedTabPosition == 0) R.color.green_39 else R.color.yellow_0b))
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
}
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = when (position) {
0 -> ResUtil.getString(R.string.record_cash_title)
1 -> ResUtil.getString(R.string.record_gold_title)
else -> null
}
}.attach()
}
companion object { companion object {
internal fun startActivity(activity: Activity) { internal fun startActivity(activity: Activity) {
activity.startActivity(Intent(activity.applicationContext, WithdrawRecordActivity::class.java)) activity.startActivity(Intent(activity.applicationContext, WithdrawRecordActivity::class.java))
@ -65,3 +98,8 @@ class WithdrawRecordActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>
} }
} }

View File

@ -0,0 +1,89 @@
package com.gamedog.vididin.features.withdrawrecord.fragments
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.ama.core.architecture.appBase.AppViewsFragment
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.setStatusBarDarkFont
import com.gamedog.vididin.features.withdrawrecord.RecordCashRvAdapter
import com.gamedog.vididin.manager.RecordsManager
import com.gamedog.vididin.manager.WithdrawManager
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlin.getValue
import com.viddin.videos.free.databinding.FragmentWithdrawRecordCashBinding as ViewBinding
import com.gamedog.vididin.features.withdrawrecord.RecordCashUiState as UiState
import com.gamedog.vididin.features.withdrawrecord.RecordCashViewModel as ViewModel
@AndroidEntryPoint
class CashRecordFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(),
OnFragmentBackgroundListener {
private lateinit var mAdapter: RecordCashRvAdapter
override val mViewModel: ViewModel by viewModels()
override var isBackgroundBright: Boolean = true
private var isStatusBarDarkFont = false
override fun inflateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
) = ViewBinding.inflate(inflater, container, false)
override fun ViewBinding.initWindowInsets() {
binding?.root?.let { setImmerseRootView(it) }
isStatusBarDarkFont = true
}
override fun ViewBinding.initViews() {
setupRecyclerView()
tvCashNum.text = buildString {
append(ResUtil.getString(R.string.cash))
append(" ")
append(WithdrawManager.instance().getHasWithdrawSuccessCashCount())
}
}
override fun ViewBinding.initListeners() {
}
override fun ViewBinding.initObservers() {
}
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
}
override fun onResume() {
super.onResume()
setStatusBarDarkFont(isDarkFont = isStatusBarDarkFont)
}
private fun setupRecyclerView() {
mAdapter = RecordCashRvAdapter()
binding?.recyclerView?.adapter = mAdapter
binding?.recyclerView?.layoutManager = LinearLayoutManager(requireContext())
lifecycleScope.launch {
mAdapter.submitList(RecordsManager.instance().getCashRecords())
}
}
companion object {
internal fun newInstance() = CashRecordFragment()
}
}

View File

@ -0,0 +1,82 @@
package com.gamedog.vididin.features.withdrawrecord.fragments
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.ama.core.architecture.appBase.AppViewsFragment
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
import com.ama.core.architecture.util.setStatusBarDarkFont
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.features.withdrawrecord.RecordGoldRvAdapter
import com.gamedog.vididin.manager.RecordsManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlin.getValue
import com.viddin.videos.free.databinding.FragmentWithdrawRecordGoldBinding as ViewBinding
import com.gamedog.vididin.features.withdrawrecord.RecordGoldUiState as UiState
import com.gamedog.vididin.features.withdrawrecord.RecordGoldViewModel as ViewModel
@AndroidEntryPoint
class GoldRecordFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(),
OnFragmentBackgroundListener {
private lateinit var mAdapter: RecordGoldRvAdapter
override val mViewModel: ViewModel by viewModels()
override var isBackgroundBright: Boolean = true
private var isStatusBarDarkFont = false
override fun inflateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
) = ViewBinding.inflate(inflater, container, false)
override fun ViewBinding.initWindowInsets() {
binding?.root?.let { setImmerseRootView(it) }
isStatusBarDarkFont = true
}
override fun ViewBinding.initViews() {
setupRecyclerView()
tvGoldNum.text = AccountManager.getGold().toString()
}
override fun ViewBinding.initListeners() {
}
override fun ViewBinding.initObservers() {
}
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
}
override fun onResume() {
super.onResume()
setStatusBarDarkFont(isDarkFont = isStatusBarDarkFont)
}
private fun setupRecyclerView() {
mAdapter = RecordGoldRvAdapter()
binding?.recyclerView?.adapter = mAdapter
binding?.recyclerView?.layoutManager = LinearLayoutManager(requireContext())
lifecycleScope.launch {
mAdapter.submitList(RecordsManager.instance().getGoldRecords())
}
}
companion object {
internal fun newInstance() = CashRecordFragment()
}
}

View File

@ -4,86 +4,242 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat import androidx.lifecycle.Lifecycle
import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.lifecycleScope
import androidx.core.view.updatePadding import androidx.lifecycle.repeatOnLifecycle
import com.ama.core.architecture.appBase.AppViewsActivity import androidx.recyclerview.widget.GridLayoutManager
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.CommonItemDecoration
import com.ama.core.architecture.util.SpUtil
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.gamedog.vididin.R import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VididinEvents
import com.viddin.videos.free.R
import com.gamedog.vididin.beans.ZeroBuyItem
import com.gamedog.vididin.beans.ZeroBuyResp
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.features.withdraw.dialogs.WithdrawSuccessDialog
import com.gamedog.vididin.features.zero.dialogs.ZeroBuyNotWinDialog
import com.gamedog.vididin.features.zero.dialogs.ZeroBuyRulesDialog
import com.gamedog.vididin.features.zero.dialogs.ZeroBuyWinDialog
import com.gamedog.vididin.manager.ZeroManager
import com.gamedog.vididin.router.Router import com.gamedog.vididin.router.Router
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlinx.coroutines.launch
import com.gamedog.vididin.databinding.ActivityZerobuyBinding as ViewBinding import com.gamedog.vididin.netbase.Result
import com.gamedog.vididin.main.MainUiState as UiState import kotlin.collections.contains
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.viddin.videos.free.databinding.ActivityZerobuyBinding as ViewBinding
@AndroidEntryPoint @AndroidEntryPoint
class ZeroBuyActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class ZeroBuyActivity : AppViewsEmptyViewModelActivity<ViewBinding>() {
private val viewModel: ZeroBuyViewModel by viewModels()
private lateinit var mAdapter: ZeroItemAdapter
override val mViewModel: ViewModel by viewModels()
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
binding.run { binding.run {
setOnClickBatch(tvZeroGoldNum, tvZeroLotteryList) { setOnClickBatch(tvZeroGoldNum, tvZeroLotteryList, llDiamondAd) {
when (this) { when (this) {
tvZeroGoldNum -> { tvZeroGoldNum -> {
} }
tvZeroLotteryList -> { tvZeroLotteryList -> {
gotoLotteryRecords() gotoLotteryRecords()
} }
llDiamondAd -> {
gotoEarnDiamond()
}
} }
} }
updateUIDiamondNum()
titlebar.setTitleText(R.string.zero_buy) titlebar.setTitleText(R.string.zero_buy)
titlebar.addRightIcon(R.mipmap.icon_question_mark, { titlebar.addRightIcon(R.mipmap.icon_question_mark, {
showHintInfo() showHintInfo()
}) })
with(recyclerView) {
mAdapter = ZeroItemAdapter({ itemId, diamondCost->
if (AccountManager.getDiamond() >= diamondCost) {
requestParticipateActivity(itemId)
} else {
AndroidUtil.showToast(R.string.dont_enought_diamond)
}
})
adapter = mAdapter
layoutManager = GridLayoutManager(this@ZeroBuyActivity, 2)
addItemDecoration(
CommonItemDecoration.create(horizontalSpace = 45, verticalSpace = 45)
)
}
} }
ZeroBuyRulesDialog(this@ZeroBuyActivity).show() StatisticUtil.reportEvents(StatisticUtil.KEY_lottery_Show)
} }
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { v, insets -> setImmerseRootView(contentRoot)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top)
insets
}
} }
private fun showHintInfo() { private fun showHintInfo() {
//TODO("Not yet implemented") ZeroBuyRulesDialog(this@ZeroBuyActivity).show()
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
//TODO("Not yet implemented") registerEvents({ data->
when (data?.mEventType) {
VididinEvents.Event_Account_Diamond_Changed -> {
updateUIDiamondNum()
}
VididinEvents.EVENT_ZERO_WITHDRAW_LIST_CHANGED -> {
checkPreWithdrawWaitNotifyResult()
}
}
}, VididinEvents.Event_Account_Diamond_Changed,
VididinEvents.EVENT_ZERO_WITHDRAW_LIST_CHANGED)
requestData()
checkPreWithdrawWaitNotifyResult()
}
private fun checkPreWithdrawWaitNotifyResult() {
val waitNotifyList = ZeroManager.instance().getWaitNotifyResultList()
waitNotifyList.forEach {
WithdrawSuccessDialog(this, cashNumStr = it.winCashNumStr).show()
ZeroManager.instance().updateHasNotifyValue(it.purchase_id)
}
}
private fun updateUIDiamondNum() {
binding.tvZeroGoldNum.text = AccountManager.getDiamond().toString()
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
//TODO("Not yet implemented") //TODO("Not yet implemented")
} }
override fun ViewBinding.onUiStateCollect(uiState: UiState) {
//TODO("Not yet implemented")
}
override fun onTabIsDarkFont(isDarkFont: Boolean) {
//TODO("Not yet implemented")
}
private fun gotoLotteryRecords() { private fun gotoLotteryRecords() {
Router.WinRecord.startActivity(this) Router.WinRecord.startActivity(this)
} }
private fun gotoEarnDiamond() {
Router.WatchAd.startActivity(this, VidiConst.WATCH_AD_FOR_ZERO_EARN_DIAMOND)
}
//----------------------- start -----------------------------
private fun requestData() {
lifecycleScope.launch {
viewModel.ZeroBuyListData.collect { result ->
when (result) {
is Result.Loading -> { showLoading(false) }
is Result.Success -> {
hideLoading()
updateUIs(result.data)
}
is Result.Error -> {
hideLoading()
}
}
}
}
viewModel.requestZeroBuyInfo()
}
private fun requestParticipateActivity(itemId: Int) {
val joinedItemIds: List<Int> = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS)
if (!joinedItemIds.contains(AccountManager.getAccount()?.userId)) {
lifecycleScope.launch {
viewModel.ZeroBuyJoinResult.collect { result ->
when (result) {
is Result.Loading -> { }
is Result.Success -> {
result.data?.let {
AccountManager.adjustDiamond(-1 * it.cost)
}
updateItemUI(result.data)
}
is Result.Error -> { AndroidUtil.showToast(R.string.has_join_failed_zerobuy) }
}
}
}
viewModel.requestJoinZeroBuy(itemId)
} else {
AndroidUtil.showToast(R.string.has_joined_zerobuy)
}
}
private fun updateUIs(data: ZeroBuyResp) {
mAdapter.submitList(data.current_purchases)
showCompletePurchasesInfo(data.finished_purchases)
}
private fun showCompletePurchasesInfo(finishedList: List<ZeroBuyItem>?) {
finishedList?.let {
val userId = AccountManager.getAccount().userId
val joinedIdList = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS)
val hasNotifiedIdList: MutableList<Int> = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_HAS_NOTIFY_IDS).toMutableList()
it.forEach { item->
if (joinedIdList.contains(item.id) && !hasNotifiedIdList.contains(item.id)) {
hasNotifiedIdList.add(item.id)
item.winners?.let {
if (it.contains(userId)) {
ZeroBuyWinDialog(this@ZeroBuyActivity, item).show()
} else {
ZeroBuyNotWinDialog(this@ZeroBuyActivity, item).show()
}
}
}
SpUtil.instance().putList(SpUtil.KEY_ZEROBUY_HAS_NOTIFY_IDS, hasNotifiedIdList)
}
}
}
private fun updateItemUI(joinedItem: ZeroBuyItem?) {
if (joinedItem == null) {
mAdapter.notifyDataSetChanged()
} else {
val currentList = mAdapter.currentList.toMutableList()
val indexToUpdate = currentList.indexOfFirst { it.id == joinedItem?.id }
if (indexToUpdate != -1) {
currentList.removeAt(indexToUpdate)
currentList.add(indexToUpdate, joinedItem)
mAdapter.submitList(currentList)
}
}
}
//----------------------- end -----------------------------
companion object { companion object {
internal fun startActivity(activity: Activity) { internal fun startActivity(activity: Activity) {
activity.startActivity(Intent(activity.applicationContext, ZeroBuyActivity::class.java)) activity.startActivity(Intent(activity.applicationContext, ZeroBuyActivity::class.java))

View File

@ -1,42 +0,0 @@
package com.gamedog.vididin.features.zero
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogZeroBuyFailBinding as ViewBinding
import com.gamedog.vididin.router.Router
class ZeroBuyFailDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
tvConfirm, ivClose -> {
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
}

View File

@ -0,0 +1,135 @@
package com.gamedog.vididin.features.zero
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DeviceUtil
import com.ama.core.architecture.util.SpUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VidiConst.ZERO_GET_PURCHASE_LIST
import com.gamedog.vididin.VidiConst.ZERO_JOIN_PURCHASE
import com.gamedog.vididin.beans.ZeroBuyItem
import com.gamedog.vididin.beans.ZeroBuyResp
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.netbase.NetworkUtil
import com.gamedog.vididin.netbase.Result
import com.gamedog.vididin.request.RequestUtil
import com.viddin.videos.free.R
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class ZeroBuyViewModel : ViewModel() {
private val CODE_HAS_JOINED_BEFORE: Int = 10003
private val _ZeroBuyListData = MutableStateFlow<Result<ZeroBuyResp>>(Result.Loading)
val ZeroBuyListData: StateFlow<Result<ZeroBuyResp>> = _ZeroBuyListData.asStateFlow()
private val _ZeroBuyJoinResult = MutableStateFlow<Result<ZeroBuyItem?>>(Result.Loading)
val ZeroBuyJoinResult: StateFlow<Result<ZeroBuyItem?>> = _ZeroBuyJoinResult.asStateFlow()
fun requestJoinZeroBuy(itemId: Int) {
viewModelScope.launch {
_ZeroBuyJoinResult.value = Result.Loading
val operationVal = ZERO_JOIN_PURCHASE
val curTimeSec = System.currentTimeMillis()/1000
val signStr = RequestUtil.getZeroBuyRequestSign(curTimeSec, operationVal)
val requestHeaders = mapOf("Operation" to operationVal.toString(), "Timestamp" to curTimeSec.toString(), "Sign" to signStr)
val requestParams: MutableMap<String, String> = mutableMapOf("AppId" to AndroidUtil.getPackageId(), "DeviceId" to DeviceUtil.generateDeviceId())
val userId = AccountManager.getAccount()?.userId?: 0
if (userId > 0) {
requestParams.put("UserId", userId.toString())
}
val joinZeroBuyItemIds = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS)
requestParams.put("ActivityId", itemId.toString())
val result = NetworkUtil.post("${VidiConst.URL_ZERO_BUY}/any", requestHeaders, requestParams, joinZeroBuyItemIds)
when (result) {
is Result.Success -> {
val respObj = AndroidUtil.json2Object<ZeroBuyResp>(result.data.string())
respObj?.let {
if (it.code == CODE_HAS_JOINED_BEFORE || it.code == 0) {
// save
val joinedActivityList = if(joinZeroBuyItemIds == null) mutableListOf<Int>() else joinZeroBuyItemIds.toMutableList()
if (!joinedActivityList.contains(itemId)) {
joinedActivityList.add(itemId)
SpUtil.instance().putList(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS, joinedActivityList)
}
// flow set
_ZeroBuyJoinResult.value = Result.Success(it.current_purchases[0])
// return
return@launch
}
}
_ZeroBuyJoinResult.value = Result.Error(Throwable("empty response"))
}
is Result.Error -> {
_ZeroBuyJoinResult.value = Result.Error(result.exception, result.message)
}
else -> { }
}
}
}
fun requestZeroBuyInfo() {
viewModelScope.launch {
_ZeroBuyListData.value = Result.Loading
val operationVal = ZERO_GET_PURCHASE_LIST
val curTimeSec = System.currentTimeMillis()/1000
val signStr = RequestUtil.getZeroBuyRequestSign(curTimeSec, operationVal)
val requestHeaders = mapOf("Operation" to operationVal.toString(), "Timestamp" to curTimeSec.toString(), "Sign" to signStr)
val requestParams: MutableMap<String, String> = mutableMapOf("AppId" to AndroidUtil.getPackageId(), "DeviceId" to DeviceUtil.generateDeviceId())
val userId = AccountManager.getAccount()?.userId?: 0
if (userId > 0) {
requestParams.put("UserId", userId.toString())
}
val joinZeroBuyItemIds = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS)
val result = NetworkUtil.post("${VidiConst.URL_ZERO_BUY}/any", requestHeaders, requestParams, joinZeroBuyItemIds)
when (result) {
is Result.Success -> {
val respObj = AndroidUtil.json2Object<ZeroBuyResp>(result.data.string())
respObj?.user_id?.let {
if (userId <= 0) {
AccountManager.saveUserIdInfo(it)
saveHasJoinedZeroIds(it, respObj.current_purchases)
}
}
_ZeroBuyListData.value = Result.Success(respObj!!)
}
is Result.Error -> {
_ZeroBuyListData.value = Result.Error(result.exception, result.message)
AndroidUtil.showToast(R.string.net_error)
}
else -> { }
}
}
}
private fun saveHasJoinedZeroIds(userId: Int, currentPurchases: List<ZeroBuyItem>) {
val joinZeroBuyItemIds = SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS).toMutableList()
currentPurchases.forEach { zero ->
zero.current_users?.let {
if (it.contains(userId) && !joinZeroBuyItemIds.contains(userId)) {
joinZeroBuyItemIds.add(zero.id)
}
}
}
SpUtil.instance().putList(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS, joinZeroBuyItemIds)
}
}

View File

@ -1,42 +0,0 @@
package com.gamedog.vididin.features.zero
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogZeroBuyWinBinding as ViewBinding
import com.gamedog.vididin.router.Router
class ZeroBuyWinDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(tvConfirm, ivClose) {
when (this) {
tvConfirm, ivClose -> {
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) }
}
}

View File

@ -0,0 +1,106 @@
package com.gamedog.vididin.features.zero
import android.os.CountDownTimer
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ama.core.architecture.util.SpUtil
import com.ama.core.architecture.util.setOnClickBatch
import com.viddin.videos.free.R
import com.gamedog.vididin.beans.ZeroBuyItem
import com.viddin.videos.free.databinding.LayoutItemZerobuyBinding as ViewBinding
class ZeroItemAdapter(private val joinCallback: (itemId: Int, diamondCost: Int)->Unit) : ListAdapter<ZeroBuyItem, ZeroItemAdapter.ViewHolder>(DiffCallback()) {
private val mBgResList = listOf<Int>(R.mipmap.zero_bg_item_sub1, R.mipmap.zero_bg_item_sub2, R.mipmap.zero_bg_item_sub3, R.mipmap.zero_bg_item_sub4)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
private fun getJoinedIdList(): List<Int> {
return SpUtil.instance().getList<Int>(SpUtil.KEY_ZEROBUY_JOINED_ACTIVITY_IDS)
}
private fun startCountDownTimer(targetTimeMs: Long) {
val countDownDuration = targetTimeMs - System.currentTimeMillis()
val mCountDownTimer = object : CountDownTimer(countDownDuration, 1000) {
override fun onTick(millisUntilFinished: Long) {
val joinedIds = getJoinedIdList()
currentList.forEach { item->
if (joinedIds.contains(item.id) && !item.completed) {
var remainSec = (item.end_time - System.currentTimeMillis()) / 1000
//item.mCountDownTimeStr =
}
}
/*long totalSeconds = millisUntilFinished / 1000;
long minutes = totalSeconds / 60;
long seconds = totalSeconds % 60;
String timeText = String . format ("%02d:%02d", minutes, seconds);
*/
}
override fun onFinish() {
}
}
mCountDownTimer.start()
}
override fun submitList(list: List<ZeroBuyItem>?) {
val sortedList = list?.sortedByDescending { it.start_time }
super.submitList(sortedList)
}
inner class ViewHolder(private val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: ZeroBuyItem) {
binding.tvTitle.text = item.title
binding.tvJoinedNum.text = item.current_users?.size.toString()
binding.tvPeopleTotal.text = "/${item.target_num}"
binding.tvJoinGoldNum.text = item.cost.toString()
binding.ivBgType.setImageResource(mBgResList[item.image])
binding.tvRewardCashNum.text = item.price
with(binding) {
setOnClickBatch(flBottomBut) {
when (this) {
flBottomBut-> {
joinCallback(item.id, item.cost)
}
}
}
// judge state
val joinedIds = getJoinedIdList()
val hasJoined = joinedIds.contains(item.id)
val hasCompleted = item.completed
flBottomBut.isVisible = !hasJoined
tvParticipateAlready.isVisible = hasJoined
//tvRemainTime.isVisible = hasJoined && !hasCompleted
}
}
}
class DiffCallback : DiffUtil.ItemCallback<ZeroBuyItem>() {
override fun areItemsTheSame(oldItem: ZeroBuyItem, newItem: ZeroBuyItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ZeroBuyItem, newItem: ZeroBuyItem): Boolean {
return false
}
}
}

View File

@ -0,0 +1,114 @@
package com.gamedog.vididin.features.zero
import android.text.SpannableString
import android.text.Spanned
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.ama.core.architecture.util.ResUtil
import com.gamedog.vididin.beans.ZeroBuyItem
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_FAIL
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_SUCCESS
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_UNSTART
import com.gamedog.vididin.manager.ZeroManager
import com.viddin.videos.free.R
import java.text.SimpleDateFormat
import com.viddin.videos.free.databinding.ZeroRecordWinBinding as ViewBinding
class ZeroRecordAdapter(private val onWithdrawCallback: (ZeroBuyItem)-> Unit) : ListAdapter<ZeroBuyItem, ZeroRecordAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
override fun submitList(list: List<ZeroBuyItem?>?) {
val sortedList = list?.sortedByDescending { it?.start_time }
super.submitList(sortedList)
}
private fun isWinItem(item: ZeroBuyItem): Boolean {
val winerIds = item.winners
return winerIds?.contains(AccountManager.getAccount().userId) ?: false
}
inner class ViewHolder(private val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: ZeroBuyItem) {
val isWinItem = isWinItem(item)
with(binding) {
tvDateWin.text = SimpleDateFormat("yyyy/MM/dd").format(item.start_time * 1000)
rlBg.setBackgroundResource(if (isWinItem) R.drawable.bg_records_win else R.drawable.bg_records_lost)
ivLeftWin.setImageResource(if (isWinItem) R.mipmap.record_win else R.mipmap.record_lost)
tvTitleWin.text = ResUtil.getString(if (isWinItem) R.string.record_win_item_title else R.string.record_lost_item_title)
tvDescWin.text = item.title
llRightWin.isVisible = isWinItem
llRightLost.isVisible = !isWinItem
if (isWinItem) {
val withdrawBean = ZeroManager.instance().getZeroWithdrawItem(item)
when (withdrawBean?.withdrawState) {
TRANSACTION_STATE_UNSTART -> {
llRightWin.isClickable = true
tvWinRightBottom.text = SpannableString(ResUtil.getString(R.string.zero_win_state_withdrarw_unstart)).apply {
setSpan(
UnderlineSpan(),
0,
this.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
TRANSACTION_STATE_FAIL -> {
llRightWin.isClickable = true
tvWinRightBottom.text = SpannableString(ResUtil.getString(R.string.zero_win_state_failed)).apply {
setSpan(
UnderlineSpan(),
0,
this.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
TRANSACTION_STATE_ONGOING -> {
llRightWin.isClickable = false
tvWinRightBottom.text = ResUtil.getString(R.string.zero_win_state_withdrarw_ongoing)
}
TRANSACTION_STATE_SUCCESS -> {
llRightWin.isClickable = false
tvWinRightBottom.text = ResUtil.getString(R.string.zero_win_state_withdrarw_success)
}
}
llRightWin.setOnClickListener {
onWithdrawCallback(item)
}
}
}
}
}
class DiffCallback : DiffUtil.ItemCallback<ZeroBuyItem>() {
override fun areItemsTheSame(oldItem: ZeroBuyItem, newItem: ZeroBuyItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ZeroBuyItem, newItem: ZeroBuyItem): Boolean {
return false
}
}
}

View File

@ -1,14 +1,14 @@
package com.gamedog.vididin.features.zero package com.gamedog.vididin.features.zero.dialogs
import android.content.Context import android.app.Activity
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogZeroBuyRuleBinding as ViewBinding import com.viddin.videos.free.databinding.DialogZeroBuyFailBinding as ViewBinding
import com.gamedog.vididin.router.Router import com.gamedog.vididin.router.Router
class ZeroBuyRulesDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) { class ZeroBuyFailDialog(context: Activity) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init { init {
build() build()
@ -33,7 +33,7 @@ class ZeroBuyRulesDialog(context: Context) : BindingDialog<ViewBinding>(context,
} }
private fun gotoWatchVideo() { private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) } Router.Withdraw.startActivity(mActivity)
} }

View File

@ -0,0 +1,41 @@
package com.gamedog.vididin.features.zero.dialogs
import android.app.Activity
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.beans.ZeroBuyItem
import com.viddin.videos.free.databinding.DialogZeroBuyNotWinBinding as ViewBinding
import com.gamedog.vididin.router.Router
class ZeroBuyNotWinDialog(context: Activity, private val item: ZeroBuyItem) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(ivClose) {
when (this) {
ivClose -> {
dismiss()
}
}
}
tvTitleSub.text = item.title + " - " + item.price
}
}
}

View File

@ -1,14 +1,14 @@
package com.gamedog.vididin.features.zero package com.gamedog.vididin.features.zero.dialogs
import android.content.Context import android.app.Activity
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogZeroBuyNotWinBinding as ViewBinding import com.viddin.videos.free.databinding.DialogZeroBuyRuleBinding as ViewBinding
import com.gamedog.vididin.router.Router import com.gamedog.vididin.router.Router
class ZeroBuyNotWinDialog(context: Context) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) { class ZeroBuyRulesDialog(context: Activity) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init { init {
build() build()
@ -33,7 +33,7 @@ class ZeroBuyNotWinDialog(context: Context) : BindingDialog<ViewBinding>(context
} }
private fun gotoWatchVideo() { private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) } Router.Withdraw.startActivity(mActivity)
} }

View File

@ -0,0 +1,55 @@
package com.gamedog.vididin.features.zero.dialogs
import android.app.Activity
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.beans.ZeroBuyItem
import com.gamedog.vididin.manager.ZeroManager
import com.viddin.videos.free.databinding.DialogZeroBuyWinBinding as ViewBinding
class ZeroBuyWinDialog(context: Activity, private val item: ZeroBuyItem) : BindingDialog<ViewBinding>(context, ViewBinding::inflate) {
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.8f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(ivClose, rlAction) {
when (this) {
ivClose -> {
dismiss()
}
rlAction -> {
handleWithdraw(item)
dismiss()
}
}
}
tvTitleSub.text = item.title
tvPurchaseReward.text = item.price
}
}
private fun handleWithdraw(item: ZeroBuyItem) {
ZeroManager.instance().addWinWithdrawItem(item)
ZeroManager.instance().startWithdrawProcess(mActivity, item)
}
}

View File

@ -1,17 +1,40 @@
package com.gamedog.vididin.core.login.login package com.gamedog.vididin.core.login.login
import com.ama.core.architecture.BaseApp
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.DateUtil import com.ama.core.architecture.util.DateUtil
import com.ama.core.architecture.util.DeviceUtil import com.ama.core.architecture.util.DeviceUtil
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.SpUtil import com.ama.core.architecture.util.SpUtil
import com.ama.core.architecture.util.eventbus.NotifyMan import com.ama.core.architecture.util.eventbus.NotifyMan
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VididinEvents import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.Account import com.gamedog.vididin.beans.Account
import com.gamedog.vididin.beans.BankInfo import com.gamedog.vididin.beans.BankInfo
import com.gamedog.vididin.beans.RECORD_CASH_PLUS_GOLD_CONVERT
import com.gamedog.vididin.beans.RECORD_GOLD_MINUS_CONVERT_2_CASH
import com.gamedog.vididin.beans.RecordCash
import com.gamedog.vididin.beans.RecordGold
import com.gamedog.vididin.manager.RecordsManager
import com.remax.notification.service.NotificationKeepAliveService
import com.viddin.videos.free.R
object AccountManager { object AccountManager {
private val mAccount: Account? by lazy { init {
NotifyMan.instance().register(object: NotifyMan.ICallback(true) {
override fun onEvent(data: NotifyMan.NotifyData<*>?) {
when (data?.mEventType) {
VididinEvents.EVENT_AD_WATCHED_FOR_ZEROBUY_EARN_DIAMOND -> {
adjustDiamond(VidiConst.DIAMOND_NUM_FOR_ONE_AD)
}
}
}
}, VididinEvents.EVENT_AD_WATCHED_FOR_ZEROBUY_EARN_DIAMOND)
}
private val mAccount: Account by lazy {
var account = SpUtil.instance().getObject<Account>(SpUtil.KEY_ACCOUNT) var account = SpUtil.instance().getObject<Account>(SpUtil.KEY_ACCOUNT)
if (account == null) { if (account == null) {
val deviceUUId = DeviceUtil.generateDeviceId() val deviceUUId = DeviceUtil.generateDeviceId()
@ -27,29 +50,89 @@ object AccountManager {
SpUtil.instance().putObject(SpUtil.KEY_ACCOUNT, mAccount) SpUtil.instance().putObject(SpUtil.KEY_ACCOUNT, mAccount)
} }
fun getAccount() : Account? {
fun updateUserName(userName: String) {
mAccount.userName = userName
saveAccountInfo()
}
//------------------------- 3个数值相关属性 增减 start --------------------------//
fun getAccount() : Account {
return mAccount return mAccount
} }
fun getGold(): Long { fun getGold(): Long {
return mAccount?.goldCount ?: 0L return mAccount.goldCount
} }
fun getCash(): Float { fun getGoldRVTimes(): Int {
return mAccount?.cashCount ?: 0F return mAccount.rvTimesGold
} }
fun addGold(newGold: Int) { fun adjustGold(adjustNum: Long, recordBean: RecordGold, isEarnByRv: Boolean = false): Boolean {
mAccount?.goldCount += newGold if (adjustNum < 0L && Math.abs(adjustNum) > getGold()) {
return false
}
mAccount.goldCount += adjustNum
if (isEarnByRv) {
mAccount.rvTimesGold++
}
saveAccountInfo() saveAccountInfo()
NotifyMan.instance().sendEvent(VididinEvents.Event_Account_Gold_Changed, null) NotifyMan.instance().sendEvent(VididinEvents.Event_Account_Gold_Changed, null)
RecordsManager.instance().appendGoldRecord(recordBean)
updateResidentNotification()
return true
} }
fun addCash(newCash: Float) { private fun updateResidentNotification() {
mAccount?.cashCount += newCash NotificationKeepAliveService.updateNotification(BaseApp.appContext())
}
fun getCash(): Double {
return mAccount.cashCount
}
fun getCashRVTimes(): Int {
return mAccount.rvTimesCash
}
@Synchronized
fun adjustCash(adjustNum: Double, recordBean: RecordCash? = null, isEarnByRv: Boolean = false): Boolean {
if (adjustNum < 0L && Math.abs(adjustNum) > getCash()) {
return false
}
mAccount.cashCount += adjustNum
if (isEarnByRv) {
mAccount.rvTimesCash++
}
saveAccountInfo() saveAccountInfo()
NotifyMan.instance().sendEvent(VididinEvents.Event_Account_Cash_Changed, null) NotifyMan.instance().sendEvent(VididinEvents.Event_Account_Cash_Changed, null)
recordBean?.let {
RecordsManager.instance().appendCashRecord(recordBean)
} }
updateResidentNotification()
return true
}
fun getDiamond(): Int {
return mAccount.diamondCount
}
@Synchronized
fun adjustDiamond(adjustNum: Int): Boolean {
if (adjustNum < 0L && Math.abs(adjustNum) > getDiamond()) {
return false
}
mAccount.diamondCount += adjustNum
saveAccountInfo()
NotifyMan.instance().sendEvent(VididinEvents.Event_Account_Diamond_Changed, null)
return true
}
//------------------------- 3个数值相关属性 增减 End --------------------------//
fun getBankInfo(): BankInfo? { fun getBankInfo(): BankInfo? {
return mAccount?.bankInfo return mAccount?.bankInfo
@ -62,14 +145,51 @@ object AccountManager {
fun saveBankAccount(bankAccount: String?) { fun saveBankAccount(bankAccount: String?) {
if (bankAccount.isNullOrEmpty()) { if (bankAccount.isNullOrEmpty()) {
mAccount?.bankInfo = null mAccount.bankInfo = null
} else { } else {
mAccount?.bankInfo = BankInfo(bankAccount=bankAccount) mAccount.bankInfo = BankInfo(bankAccount=bankAccount)
} }
saveAccountInfo() saveAccountInfo()
NotifyMan.instance().sendEvent( NotifyMan.instance().sendEvent(
VididinEvents.Event_Account_Bank_Info_Changed, NotifyMan.NotifyData(bankAccount)) VididinEvents.EVENT_BANK_INFO_CHANGED, NotifyMan.NotifyData(bankAccount))
} }
@Synchronized
fun convertGold2Cash(): Boolean {
try {
val couldCovertCashTotal = getGold().div(VidiConst.PER_01CASH_COST_GOLD_NUM) ?: 0
if (couldCovertCashTotal > 0) {
val costGoldNum = couldCovertCashTotal * VidiConst.PER_01CASH_COST_GOLD_NUM
if (getGold() >= costGoldNum) {
adjustGold(-1L * costGoldNum.toInt(), RecordGold(RECORD_GOLD_MINUS_CONVERT_2_CASH, -1L * costGoldNum.toInt()))
val adjustCashNum = couldCovertCashTotal * 0.1
adjustCash(adjustCashNum, RecordCash(RECORD_CASH_PLUS_GOLD_CONVERT, adjustCashNum.toDouble()), true)
AndroidUtil.showCustomToast(String.format(ResUtil.getString(R.string.has_claim_box_cash_hint), adjustCashNum))
return true
}
} else {
AndroidUtil.showToast(ResUtil.getString(R.string.not_enough_gold))
}
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
fun saveUserIdInfo(userId: Int) {
mAccount?.let {
it.userId = userId
saveAccountInfo()
}
}
fun isBankAccountExist(): Boolean {
return !mAccount?.bankInfo?.bankAccount.isNullOrEmpty()
}
} }

View File

@ -7,7 +7,7 @@ import android.view.LayoutInflater
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity
import com.gamedog.vididin.databinding.VididinappFeatureLoginActivityLoginBinding as ViewBinding import com.viddin.videos.free.databinding.VididinappFeatureLoginActivityLoginBinding as ViewBinding
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.jvm.java import kotlin.jvm.java

View File

@ -1,14 +1,29 @@
package com.gamedog.vididin.main package com.gamedog.vididin.main
import android.app.Activity import android.app.Activity
import android.content.Context import android.widget.FrameLayout
import androidx.core.graphics.toColorInt
import com.ama.core.architecture.highlightpro.HighlightPro
import com.ama.core.architecture.highlightpro.parameter.Constraints
import com.ama.core.architecture.highlightpro.parameter.HighlightParameter
import com.ama.core.architecture.highlightpro.parameter.MarginOffset
import com.ama.core.architecture.highlightpro.shape.RectShape
import com.ama.core.architecture.util.ResUtil.dp
import com.ama.core.architecture.util.SpUtil
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogBeginnerGiftBinding import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.router.Router import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VidiConst.GUIDE_INDEX_GIFT
import com.gamedog.vididin.beans.RECORD_GOLD_PLUS_NEWBIE_GIFT
import com.gamedog.vididin.beans.RecordGold
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.manager.GuideManager
import com.viddin.videos.free.R
import com.viddin.videos.free.databinding.DialogBeginnerGiftBinding
class BeginnerGiftDialog(context: Context) : BindingDialog<DialogBeginnerGiftBinding>(context, DialogBeginnerGiftBinding::inflate) { class BeginnerGiftDialog(activity: Activity) : BindingDialog<DialogBeginnerGiftBinding>(activity, DialogBeginnerGiftBinding::inflate) {
init { init {
build() build()
@ -25,16 +40,55 @@ class BeginnerGiftDialog(context: Context) : BindingDialog<DialogBeginnerGiftBin
setOnClickBatch(tvAction) { setOnClickBatch(tvAction) {
when (this) { when (this) {
tvAction -> { tvAction -> {
gotoWatchVideo() handleClickEvent()
}
}
}
}
showGuide()
}
private fun handleClickEvent() {
if (mActivity is MainActivity) {
(mActivity as MainActivity).switchTab(1)
}
if (!SpUtil.instance().getBoolean(SpUtil.KEY_GUIDE_HAS_GOT_NEWBIE_GOLD)) {
AccountManager.adjustGold(VidiConst.NEWBIE_GIFT_GOLD_NUM, RecordGold(RECORD_GOLD_PLUS_NEWBIE_GIFT, VidiConst.NEWBIE_GIFT_GOLD_NUM))
SpUtil.instance().putBoolean(SpUtil.KEY_GUIDE_HAS_GOT_NEWBIE_GOLD, true)
}
dismiss() dismiss()
} }
}
}
}
}
private fun gotoWatchVideo() {
ownerActivity?.let { Router.Withdraw.startActivity(it) } private fun showGuide() {
HighlightPro.with(window?.decorView as FrameLayout)
.setHighlightParameter {
HighlightParameter.Builder()
.setHighlightView(mBinding.tvAction, {
val temp = 111
})
.setTipsViewId(R.layout.guide_step_withdraw)
.setHighlightShape(RectShape(22.dp, 22.dp, 22.dp))
.setHighlightHorizontalPadding(0.dp)
.setConstraints(Constraints.TopToBottomOfHighlight + Constraints.EndToEndOfHighlight)
.setMarginOffset(MarginOffset(top = -22.dp.toInt(), end = -10.dp.toInt()))
.build()
}
.setBackgroundColor("#00000000".toColorInt())
.setOnShowCallback { index ->
}
.setOnDismissCallback {
GuideManager.instance().setGuideIndex(GUIDE_INDEX_GIFT)
handleClickEvent()
}
.interceptBackPressed(true)
.show()
StatisticUtil.reportEvents(StatisticUtil.KEY_Guide, mapOf("Guide" to 1))
} }

View File

@ -1,61 +1,91 @@
package com.gamedog.vididin.main package com.gamedog.vididin.main
import android.app.Activity
import com.ama.core.common.util.asSafe import android.content.BroadcastReceiver
import androidx.core.view.ViewCompat import android.content.ComponentName
import androidx.core.view.WindowInsetsCompat import android.content.Intent
import androidx.fragment.app.Fragment import android.content.IntentFilter
import androidx.fragment.app.FragmentManager import android.content.pm.PackageManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import androidx.viewpager2.widget.ViewPager2
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import com.ama.core.architecture.appBase.AppViewsActivity import com.ama.core.architecture.appBase.AppViewsActivity
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
import com.ama.core.architecture.ext.toast import com.ama.core.architecture.ext.toast
import com.ama.core.architecture.util.DateUtil
import com.ama.core.architecture.util.bindViewPager2 import com.ama.core.architecture.util.bindViewPager2
import com.ama.core.architecture.util.setCommonNavigator import com.ama.core.architecture.util.setCommonNavigator
import com.ama.core.architecture.util.setDataOrAdapter import com.ama.core.architecture.util.setDataOrAdapter
import com.gamedog.vididin.R import com.ama.core.common.util.asSafe
import com.blankj.utilcode.util.ActivityUtils
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VidiConst.GUIDE_INDEX_GIFT
import com.gamedog.vididin.VidiConst.GUIDE_INDEX_ZERO
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.adapter.MainTabsAdapter import com.gamedog.vididin.adapter.MainTabsAdapter
import com.gamedog.vididin.adapter.MainViewPagerAdapter import com.gamedog.vididin.adapter.MainViewPagerAdapter
import com.gamedog.vididin.main.fragments.task.DailySignSuccessDialog
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.main.interfaces.OnTabStyleListener
import com.gamedog.vididin.manager.DateChangeReceiver
import com.gamedog.vididin.manager.GuideManager
import com.gamedog.vididin.manager.NotificationController
import com.gamedog.vididin.router.Router
import com.remax.base.report.DataReportManager
import com.remax.base.utils.ActivityLauncher
import com.remax.bill.ads.AdResult
import com.remax.bill.ads.PreloadController
import com.remax.bill.ads.ext.AdShowExt
import com.remax.bill.ads.log.AdLogger
import com.remax.notification.builder.LANDING_NOTIFICATION_ACTION
import com.remax.notification.builder.LANDING_NOTIFICATION_CONTENT
import com.remax.notification.builder.LANDING_NOTIFICATION_FROM
import com.remax.notification.builder.LANDING_NOTIFICATION_TITLE
import com.remax.notification.check.NotificationCheckController
import com.remax.notification.config.PushContent
import com.remax.notification.controller.NotificationLandingController
import com.remax.notification.newUtil.events.AppInstallReceiver
import com.remax.notification.newUtil.events.PowerConnectionReceiver
import com.remax.notification.service.NotificationKeepAliveServiceManager
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlinx.coroutines.launch
import com.gamedog.vididin.databinding.ActivityMainBinding as ViewBinding import kotlin.math.ceil
import com.gamedog.vididin.main.MainUiState as UiState import com.gamedog.vididin.main.MainUiState as UiState
import com.gamedog.vididin.main.MainViewModel as ViewModel import com.gamedog.vididin.main.MainViewModel as ViewModel
import com.viddin.videos.free.databinding.ActivityMainBinding as ViewBinding
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener { class MainActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabStyleListener {
private lateinit var mAppInstallReceiver: AppInstallReceiver
private lateinit var mPowerReceiver: BroadcastReceiver
private lateinit var activityLauncher: ActivityLauncher
override val mViewModel: ViewModel by viewModels() override val mViewModel: ViewModel by viewModels()
private lateinit var navigatorAdapter: MainTabsAdapter private lateinit var navigatorAdapter: MainTabsAdapter
private val fragmentStateAdapter by lazy { MainViewPagerAdapter(this) } private val fragmentStateAdapter by lazy { MainViewPagerAdapter(this) }
private lateinit var mDateChangeReceiver: DateChangeReceiver
override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater)
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(magicIndicator) { v, insets -> setImmerseRootView(flForImmerse)
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout())
v.setPadding(
systemBars.left,
36,
systemBars.right,
systemBars.bottom + 36
)
insets
}
} }
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
content.foreground.alpha = 0 onAdShowingStateChanged(false)
activityLauncher = ActivityLauncher(this@MainActivity)
navigatorAdapter = MainTabsAdapter( navigatorAdapter = MainTabsAdapter(
this@MainActivity, viewPager2, fragmentStateAdapter, magicIndicator this@MainActivity, viewPager2, fragmentStateAdapter, magicIndicator
) )
@ -67,10 +97,21 @@ class MainActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabS
viewPager2.offscreenPageLimit viewPager2.offscreenPageLimit
if (GuideManager.instance().getCurGuideIndex() < GUIDE_INDEX_GIFT) {
BeginnerGiftDialog(this@MainActivity).show() BeginnerGiftDialog(this@MainActivity).show()
} }
if (intent.getBooleanExtra(EXTRA_NEED_SHOW_SPLASH_AD, false)) {
showSplashAd()
}
}
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
mDateChangeReceiver = DateChangeReceiver()
val filter = IntentFilter(Intent.ACTION_DATE_CHANGED)
registerReceiver(mDateChangeReceiver, filter)
registerReceivers()
onBackPressedDispatcher.addCallback(this@MainActivity) { onBackPressedDispatcher.addCallback(this@MainActivity) {
if (mViewModel.canBack) { if (mViewModel.canBack) {
finish() finish()
@ -97,10 +138,34 @@ class MainActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabS
onTabIsDarkFont(isBackgroundBright) onTabIsDarkFont(isBackgroundBright)
} }
}, false) }, false)
registerEvents( { data->
when (data?.mEventType) {
VididinEvents.EVENT_AD_WATCHED_FOR_EARN_GOLD-> {
DailySignSuccessDialog(this@MainActivity).initData(VidiConst.WATCH_AD_REWARD_GOLD.toInt(), false).show()
}
VididinEvents.EVENT_JUMP_2_VIDEO-> {
switchTab(0)
}
VididinEvents.AD_ACT_SHOWING-> {
onAdShowingStateChanged(true)
}
VididinEvents.AD_ACT_DESTROY-> {
onAdShowingStateChanged(false)
}
}
}, VididinEvents.EVENT_AD_WATCHED_FOR_EARN_GOLD, VididinEvents.EVENT_JUMP_2_VIDEO,
VididinEvents.AD_ACT_SHOWING, VididinEvents.AD_ACT_DESTROY)
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
checkNotifyPermissionAndStartService()
handleNotificationAction()
reportStatistics(intent, true)
} }
@ -112,9 +177,244 @@ class MainActivity : AppViewsActivity<ViewBinding, UiState, ViewModel>(), OnTabS
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
StatisticUtil.reportEvents(StatisticUtil.KEY_Home_Show)
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(mDateChangeReceiver)
unregisterReceivers()
} }
override fun onTabIsDarkFont(isDarkFont: Boolean) { override fun onTabIsDarkFont(isDarkFont: Boolean) {
navigatorAdapter.setIsDarkFont(isDarkFont) navigatorAdapter.setIsDarkFont(isDarkFont)
} }
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleNotificationAction()
reportStatistics(intent, true)
}
private fun onAdShowingStateChanged(isAdShowing: Boolean) {
val newState = if (isAdShowing) {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
} else {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
}
packageManager.setComponentEnabledSetting(
ComponentName(this, "com.gamedog.vididin.main.MainActivityAlias"),
newState,
PackageManager.DONT_KILL_APP
)
}
fun switchTab(itemIndex: Int) {
binding.viewPager2.setCurrentItem(itemIndex, false)
}
private fun handleNotificationAction() {
if (NotificationLandingController.isFromNotification(intent)) {
val notificationAction = intent.getIntExtra(LANDING_NOTIFICATION_ACTION, -1)
when (notificationAction) {
PushContent.ACTION_TYPE_GAME -> {
Router.Game.startActivity(this)
}
PushContent.ACTION_TYPE_GOLD -> {
switchTab(1)
}
PushContent.ACTION_TYPE_WITHDRAW -> {
Router.Withdraw.startActivity(this)
}
PushContent.ACTION_TYPE_BOX -> {
Router.Benefit.startActivity(this)
}
}
NotificationLandingController.clearNotificationParameters(intent)
sendNotificationClickStatistics(notificationAction)
}
}
private fun showSplashAd() {
val startTime = DateUtil.getCurTimeMs()
lifecycleScope.launch {
when (val result = AdShowExt.showAppOpenAd(this@MainActivity) { loaded ->
PreloadController.preload(this@MainActivity)
PreloadController.preloadPangle(this@MainActivity)
PreloadController.preloadTopOn(this@MainActivity)
DataReportManager.reportData(
"loading_page_end", mapOf(
"pass_time" to ceil((System.currentTimeMillis() - startTime) / 1000.0).toInt()
)
)
}) {
is AdResult.Success -> {
AdLogger.e("开屏广告显示成功 in MainAct")
}
is AdResult.Failure -> {
AdLogger.e("开屏广告显示失败 in MainAct: ${result.error.message} ")
}
AdResult.Loading -> {
AdLogger.d("开屏广告显示中... in MainAct")
}
}
}
}
private fun sendNotificationClickStatistics(notificationAction: Int) {
var pushType = 1
if (notificationAction == PushContent.ACTION_TYPE_GAME
|| notificationAction == PushContent.ACTION_TYPE_GOLD
|| notificationAction == PushContent.ACTION_TYPE_WITHDRAW
|| notificationAction == PushContent.ACTION_TYPE_BOX ) {
pushType = 2
}
StatisticUtil.reportEvents(StatisticUtil.KEY_Push_Click, mapOf(
"Push_Position" to pushType,
"Push_Type" to pushType
))
StatisticUtil.reportEvents(StatisticUtil.KEY_Push_EnterGame, mapOf(
"Push_Position" to pushType,
"Push_Type" to pushType
))
}
private fun checkNotifyPermissionAndStartService() {
if (GuideManager.instance().getCurGuideIndex() > GUIDE_INDEX_ZERO) {
NotificationController.requestNotificationPermissionAsAsync(
context = this,
lifecycleScope = lifecycleScope,
activityLauncher = activityLauncher!!,
position = "Appstart",
onGrantedOnlyUnauthorized = { isGranted->
if(isGranted){
NotificationKeepAliveServiceManager.startKeepAliveService(this)
}
})
}
}
private fun reportStatistics(intent: Intent, isFromNewIntent: Boolean) {
// AppOpen
DataReportManager.reportData(
VidiConst.STATISTICS_APP_OPEN,
mapOf(
"type" to if (ActivityUtils.isActivityExistsInStack(MainActivity::class.java)) "hot_open" else "cold_open",
"position" to if (intent.hasExtra(LANDING_NOTIFICATION_FROM)) intent.getStringExtra(
LANDING_NOTIFICATION_FROM).orEmpty().ifBlank { "other" } else "other"
))
// Notific_Click
if (intent.hasExtra(LANDING_NOTIFICATION_FROM)) {
val notifyFrom = intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()
DataReportManager.reportData(
VidiConst.STATISTICS_NOTIFI_CLICK, mapOf(
"Notific_Type" to when (notifyFrom) {
NotificationCheckController.NotificationType.UNLOCK.string -> 1
NotificationCheckController.NotificationType.BACKGROUND.string -> 1
NotificationCheckController.NotificationType.FIXTIMEPOINT.string -> 1
NotificationCheckController.NotificationType.KEEPALIVE.string -> 1
NotificationCheckController.NotificationType.FCM.string -> 3
NotificationCheckController.NotificationType.RESIDENT.string -> 4
else -> 4
},
"Notific_Position" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> 2
else -> 1
},
"Notific_Priority" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> "PRIORITY_DEFAULT"
else -> "PRIORITY_MAX"
},
"event_id" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> "permanent"
else -> "customer_general_style"
},
"title" to intent.getStringExtra(LANDING_NOTIFICATION_TITLE).orEmpty(),
"text" to intent.getStringExtra(LANDING_NOTIFICATION_CONTENT).orEmpty(),
"from_background" to /*!ActivityUtils.isActivityExistsInStack(HomeActivity::class.java)*/isFromNewIntent
)
)
DataReportManager.reportData(
VidiConst.STATISTICS_NOTIFI_ENTER, mapOf(
"Notific_Type" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.UNLOCK.string -> 1
NotificationCheckController.NotificationType.BACKGROUND.string -> 1
NotificationCheckController.NotificationType.FIXTIMEPOINT.string -> 1
NotificationCheckController.NotificationType.KEEPALIVE.string -> 1
NotificationCheckController.NotificationType.FCM.string -> 3
NotificationCheckController.NotificationType.RESIDENT.string -> 4
else -> 4
},
"Notific_Position" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> 2
else -> 1
},
"Notific_Priority" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> "PRIORITY_DEFAULT"
else -> "PRIORITY_MAX"
},
"event_id" to when (intent.getStringExtra(LANDING_NOTIFICATION_FROM).orEmpty()) {
NotificationCheckController.NotificationType.RESIDENT.string -> "permanent"
else -> "customer_general_style"
},
"title" to intent.getStringExtra(LANDING_NOTIFICATION_TITLE).orEmpty(),
"text" to intent.getStringExtra(LANDING_NOTIFICATION_CONTENT).orEmpty(),
)
)
}
}
private fun registerReceivers() {
mPowerReceiver = PowerConnectionReceiver()
val filter1 = IntentFilter().apply {
addAction(Intent.ACTION_POWER_CONNECTED)
addAction(Intent.ACTION_POWER_DISCONNECTED)
}
registerReceiver(mPowerReceiver, filter1)
mAppInstallReceiver = AppInstallReceiver()
val filter2 = IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REPLACED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package")
}
registerReceiver(mAppInstallReceiver, filter2)
}
private fun unregisterReceivers() {
unregisterReceiver(mPowerReceiver)
unregisterReceiver(mAppInstallReceiver)
}
companion object {
val EXTRA_NEED_SHOW_SPLASH_AD = "EXTRA_NEED_SHOW_SPLASH_AD"
internal fun startActivity(activity: Activity, needShowSplashAd: Boolean) {
val intent = Intent(activity.applicationContext, MainActivity::class.java).apply {
putExtra(EXTRA_NEED_SHOW_SPLASH_AD, needShowSplashAd)
}
activity.startActivity(intent)
}
}
} }

View File

@ -1,10 +1,10 @@
package com.gamedog.vididin.main package com.gamedog.vididin.main
import android.util.TimeUtils
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.ama.core.architecture.appBase.vm.AppViewModel import com.ama.core.architecture.appBase.vm.AppViewModel
import com.gamedog.vididin.R import com.viddin.videos.free.R
import com.gamedog.vididin.beans.MainTabsItem import com.gamedog.vididin.beans.MainTabsItem
import com.gamedog.vididin.repository.MainRepository import com.gamedog.vididin.repository.MainRepository
import com.gamedog.vididin.repository.MainTabType import com.gamedog.vididin.repository.MainTabType

View File

@ -0,0 +1,102 @@
package com.gamedog.vididin.main
import android.app.Activity
import androidx.core.view.isVisible
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiStatisticHelper
import com.viddin.videos.free.databinding.DialogWatchVideoBinding
import com.gamedog.vididin.router.Router
class WatchAdDialog(context: Activity, private val mWatchAdType: Int, statisticType: Int, private val mGoldNum: Int? = 0,
private val mTaskDataJson: String? = "")
: BindingDialog<DialogWatchVideoBinding>(context, DialogWatchVideoBinding::inflate) {
private var mOnClosed: (() -> Unit)? = null
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.93f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(flAction, ivClose) {
when (this) {
ivClose -> {
mOnClosed?.invoke()
dismiss()
}
flAction -> {
gotoWatchVideo()
sendClickStatistic()
}
}
}
mGoldNum?.let {
tvGoldNum.text = "+$mGoldNum"
}
if (mGoldNum == null) {
tvGoldNum.isVisible = false
}
}
sendShowStatistic()
}
private fun sendShowStatistic() {
StatisticUtil.reportEvents(StatisticUtil.KEY_RV_Button_Show, mapOf("Position" to VidiStatisticHelper.getShowFromStr(mWatchAdType)))
}
private fun sendClickStatistic() {
StatisticUtil.reportEvents(StatisticUtil.KEY_RV_Button_Click, mapOf("Position" to VidiStatisticHelper.getShowFromStr(mWatchAdType)))
}
private fun gotoWatchVideo() {
Router.WatchAd.startActivity(mActivity, mWatchAdType, mTaskDataJson)
dismiss()
}
fun setOnCloseListener(onClose: ()->Unit) {
mOnClosed = onClose
}
companion object {
val FROM_WATCH_5VIDEOS: Int = 1
val FROM_TASK_FRAGMENT_ICON: Int = 2
/*val FROM_SIGN_AD_FOR_DOUBLE: Int = 3
val FROM_SIGN_AD_FOR_EXTRA: Int = 4
val FROM_SIGN_AD_FOR_SUPPLEMENT: Int = 5
val FROM_WITHDRAW_PROGRESS: Int = 6*/
val FROM_DIALY_TASKS: Int = 7
val FROM_CONVERT_GOLD_TO_CASH: Int = 8
val FROM_HOME_MENU: Int = 9
/*1每观看5个视频后插入一条激励视频广告用户可选择观看完15-30秒广告以获得大额金币奖励
2"看视频获得金币奖励
3"签到页面观看视频获得双倍奖励
4签到页面观看视频获得额外奖励
5签到页面观看视频进行补签
6观看视频加速小额进度提现
7观看视频加速大额进度提现
8观看视频可以金币兑换现金*/
}
}

View File

@ -1,46 +0,0 @@
package com.gamedog.vididin.main
import android.content.Context
import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.widget.BindingDialog
import com.gamedog.vididin.databinding.DialogWatchVideoBinding
import com.gamedog.vididin.main.fragments.task.RewardDetail
class WatchVideoDialog(context: Context) : BindingDialog<DialogWatchVideoBinding>(context, DialogWatchVideoBinding::inflate) {
private lateinit var mDataList: List<RewardDetail>
init {
build()
}
private fun build() {
with()
setCenter()
setMaskValue(0.93f)
setCanCancel(false)
mBinding.run {
setOnClickBatch(flAction, ivClose) {
when (this) {
ivClose -> {
dismiss()
}
flAction -> {
gotoWatchVideo()
dismiss()
}
}
}
}
}
private fun gotoWatchVideo() {
}
}

View File

@ -1,10 +1,10 @@
package com.gamedog.vididin.main.fragments package com.gamedog.vididin.main.fragments
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat import androidx.core.graphics.toColorInt
import androidx.core.view.WindowInsetsCompat import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
@ -13,16 +13,39 @@ import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.ama.core.architecture.appBase.AppViewsFragment import com.ama.core.architecture.appBase.AppViewsFragment
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
import com.ama.core.architecture.highlightpro.HighlightPro
import com.ama.core.architecture.highlightpro.parameter.Constraints
import com.ama.core.architecture.highlightpro.parameter.HighlightParameter
import com.ama.core.architecture.highlightpro.parameter.MarginOffset
import com.ama.core.architecture.highlightpro.shape.OvalShape
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.ResUtil.dp
import com.ama.core.architecture.util.setStatusBarDarkFont import com.ama.core.architecture.util.setStatusBarDarkFont
import com.ama.core.common.util.asSafe import com.ama.core.common.widget.PopMenuView
import com.gamedog.statisticreporter.StatisticUtil
import com.gamedog.vididin.VidiConst
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.RECORD_GOLD_PLUS_WATCH_VIDEO_BY_TIME_DURATION
import com.gamedog.vididin.beans.RecordGold
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.main.WatchAdDialog
import com.gamedog.vididin.main.fragments.home.HomeFragmentStateAdapter import com.gamedog.vididin.main.fragments.home.HomeFragmentStateAdapter
import com.gamedog.vididin.main.fragments.home.fragment.HomeItemFragment import com.gamedog.vididin.main.fragments.home.fragment.HomeItemFragment
import com.gamedog.vididin.main.interfaces.OnSwitchTabListener import com.gamedog.vididin.main.interfaces.OnSwitchTabListener
import com.gamedog.vididin.main.interfaces.OnTabStyleListener import com.gamedog.vididin.manager.GuideManager
import com.gamedog.vididin.manager.TaskManager
import com.gamedog.vididin.manager.TestingManager
import com.gamedog.vididin.router.Router
import com.gamedog.vididin.youtubestatistic.RewardConst
import com.gamedog.vididin.youtubestatistic.RewardConst.Companion.Check_Interval_MS
import com.remax.bill.ads.AdResult
import com.remax.bill.ads.ext.AdShowExt
import com.remax.notification.BuildConfig
import com.viddin.videos.free.R
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.VididinappFeatureHomeFragmentHomeBinding as ViewBinding import com.viddin.videos.free.databinding.VididinappFeatureHomeFragmentHomeBinding as ViewBinding
import com.gamedog.vididin.main.fragments.home.YoutubeViewModel as ViewModel import com.gamedog.vididin.main.fragments.home.YoutubeViewModel as ViewModel
import com.gamedog.vididin.main.fragments.home.YoutubeUiState as UiState import com.gamedog.vididin.main.fragments.home.YoutubeUiState as UiState
@ -30,9 +53,16 @@ import com.gamedog.vididin.main.fragments.home.YoutubeUiState as UiState
@AndroidEntryPoint @AndroidEntryPoint
class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwitchTabListener, OnFragmentBackgroundListener { class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwitchTabListener, OnFragmentBackgroundListener {
private var mWatchedVideoTotal = 0
private var mSwipedVideoTotal = 0
private var mLastShowedRewardedAd = true
override val isLazyInit = false
private var mHasShowGuide: Boolean = false
private var mTotalMs: Long = 0L
override val mViewModel: ViewModel by viewModels() override val mViewModel: ViewModel by viewModels()
override var isBackgroundBright: Boolean = true override var isBackgroundBright: Boolean = true
private var isStatusBarDarkFont = false
private val mViewPagerAdapter by lazy { HomeFragmentStateAdapter(this) } private val mViewPagerAdapter by lazy { HomeFragmentStateAdapter(this) }
@ -42,32 +72,179 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
) = ViewBinding.inflate(inflater, container, false) ) = ViewBinding.inflate(inflater, container, false)
override fun ViewBinding.initWindowInsets() { override fun ViewBinding.initWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(viewPager2) { v, insets -> /*ViewCompat.setOnApplyWindowInsetsListener(viewPager2) { v, insets ->
val systemBars = val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
v.updatePadding(top = systemBars.top) v.updatePadding(top = systemBars.top)
insets insets
} }*/
} }
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
viewPager2.setPageTransformer { _, _ -> } viewPager2.setPageTransformer { _, _ -> }
viewPager2.offscreenPageLimit = 1 viewPager2.offscreenPageLimit = 1
viewPager2.adapter = mViewPagerAdapter viewPager2.adapter = mViewPagerAdapter
popMenu.setMenuList(
mutableListOf(
PopMenuView.MenuItem(R.mipmap.home_menu_1, 0, 0) {
Router.Benefit.startActivity(requireActivity())
},
PopMenuView.MenuItem(R.mipmap.home_menu_2,R.mipmap.icon_gold_ss_new, 0) {
WatchAdDialog(requireActivity(), VidiConst.WATCH_AD_FOR_DAILY_EARN_GOLD_POPMENU, WatchAdDialog.FROM_HOME_MENU,null).show()
},
PopMenuView.MenuItem(R.mipmap.home_menu_3,0, 0) {
Router.Game.startActivity(requireActivity())
},
PopMenuView.MenuItem(R.mipmap.home_menu_4,0, 0) {
Router.ZeroBuy.startActivity(requireActivity())
}
))
updatePopMenuTexts()
registerEvents({ data->
when (data?.mEventType) {
VididinEvents.Event_HOME_WATCH_Time_TICK -> {
handleWatchTimeTick()
}
VididinEvents.Event_Finish_One_Video -> {
handleEventOneVideoWatched()
}
VididinEvents.EVENT_BOX_TASK_STATE_CHANGED -> {
updatePopMenuTexts()
}
}
}, VididinEvents.Event_HOME_WATCH_Time_TICK, VididinEvents.Event_Finish_One_Video, VididinEvents.EVENT_BOX_TASK_STATE_CHANGED)
}
private fun updatePopMenuTexts() {
for (index in 0..3) {
var textStr = ""
when (index) {
3 -> {
textStr = TaskManager.instance().boxTaskStatus().getLeftValidBoxTotalDurationStr()
}
2 -> {
textStr = VidiConst.WATCH_AD_REWARD_GOLD.toString()
}
1 -> {
textStr = ResUtil.getString(R.string.game_discord)
}
0 -> {
textStr = ResUtil.getString(R.string.zero_buy_tag)
}
}
binding?.popMenu?.setMenuText(index, textStr)
}
}
private fun showGuide() {
HighlightPro.with(this@HomeFragment)
.setHighlightParameter {
HighlightParameter.Builder()
.setHighlightView(binding?.popMenu!!, {
})
.setTipsViewId(R.layout.guide_step_popmnue)
.setHighlightShape(OvalShape(binding?.popMenu?.measuredWidth!!.toFloat()/2))
.setHighlightHorizontalPadding(0.dp)
.setConstraints(Constraints.TopToBottomOfHighlight + Constraints.EndToEndOfHighlight)
.setMarginOffset(MarginOffset(top = -20.dp.toInt(), end = 20.dp.toInt()))
.build()
}
.setBackgroundColor("#cc000000".toColorInt())
.setOnShowCallback { index ->
}
.setOnDismissCallback {
saveGuideState()
binding?.popMenu!!.toggleMenu()
}
.interceptBackPressed(true)
.show()
StatisticUtil.reportEvents(StatisticUtil.KEY_Guide, mapOf("Guide" to 5))
}
private fun saveGuideState() {
GuideManager.instance().setGuideIndex(VidiConst.GUIDE_INDEX_POP_MENU)
}
private fun handleEventOneVideoWatched() {
mWatchedVideoTotal++
if (mWatchedVideoTotal % VIDEO_NUM_GAP_FOR_AD_WATCHED == 0) {
if (mLastShowedRewardedAd) {
showInterstitialAd {}
} else {
handleShouldShowAdDialog()
}
// reset state
mLastShowedRewardedAd = !mLastShowedRewardedAd
mWatchedVideoTotal = 0
mSwipedVideoTotal = 0
}
}
private fun handleEventOneVideoSwiped() {
mSwipedVideoTotal ++
if (mSwipedVideoTotal % VIDEO_NUM_GAP_FOR_AD_SWIPED == 0) {
if (mLastShowedRewardedAd) {
showInterstitialAd {}
} else {
handleShouldShowAdDialog()
}
// reset state
mLastShowedRewardedAd = !mLastShowedRewardedAd
mWatchedVideoTotal = 0
mSwipedVideoTotal = 0
}
}
private fun handleWatchTimeTick() {
mTotalMs += Check_Interval_MS
if (mTotalMs < RewardConst.HOME_WATCH_DURATION) {
binding?.dragIconView?.setProgress(mTotalMs * 100/RewardConst.HOME_WATCH_DURATION)
} else {
mTotalMs = 0L
binding?.dragIconView?.setProgress(mTotalMs * 100/ RewardConst.HOME_WATCH_DURATION)
val goldNum = RewardConst.HOME_WATCH_REWARD_NUM.toLong()
AccountManager.adjustGold(goldNum, RecordGold(RECORD_GOLD_PLUS_WATCH_VIDEO_BY_TIME_DURATION, goldNum))
binding?.dragIconView?.showRewardGoldAnim()
}
} }
override fun ViewBinding.initListeners() { override fun ViewBinding.initListeners() {
viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
super.onPageSelected(position) super.onPageSelected(position)
setHomeTabStyle(mViewPagerAdapter.getFragmentByIndex(position)) val fragment = mViewPagerAdapter.getFragmentByIndex(position)
val curFragment: HomeItemFragment = mViewPagerAdapter.getFragmentByIndex(position) as HomeItemFragment if (fragment != null) {
setHomeTabStyle(fragment)
val curFragment: HomeItemFragment = fragment as HomeItemFragment
curFragment.loadVideo() curFragment.loadVideo()
handleEventOneVideoSwiped()
}
// load more // load more
if (mViewPagerAdapter.itemCount > 0 && position == mViewPagerAdapter.itemCount - 2) { if (mViewPagerAdapter.itemCount > 0 && position == mViewPagerAdapter.itemCount - 2) {
lifecycleScope.launch { lifecycleScope.launch {
mViewModel.loadVideoPage() mViewModel.loadVideoList()
} }
} }
} }
@ -81,9 +258,11 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
FragmentLifecycleCallbacks() { FragmentLifecycleCallbacks() {
override fun onFragmentResumed(fm: FragmentManager, fra: Fragment) { override fun onFragmentResumed(fm: FragmentManager, fra: Fragment) {
super.onFragmentResumed(fm, fra) super.onFragmentResumed(fm, fra)
setHomeTabStyle(fra)
} }
}, false) }, false)
viewPager2.offscreenPageLimit = 3
} }
override fun ViewBinding.initObservers() { override fun ViewBinding.initObservers() {
@ -91,13 +270,22 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
} }
override fun ViewBinding.onUiStateCollect(uiState: UiState) { override fun ViewBinding.onUiStateCollect(uiState: UiState) {
mViewPagerAdapter.submitList(uiState.playLists) mViewPagerAdapter.submitList(uiState.playLists?.toList())
//viewPager2.setDataOrAdapter(uiState.playLists, 1) { mViewPagerAdapter }
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
setStatusBarDarkFont(isDarkFont = isBackgroundBright) setStatusBarDarkFont(isDarkFont = isStatusBarDarkFont)
if (!mHasShowGuide) {
val guideStateValue = GuideManager.instance().getCurGuideIndex()
if (binding?.popMenu?.isVisible == true && guideStateValue == VidiConst.GUIDE_INDEX_ZERO) {
binding?.popMenu?.postDelayed({
showGuide()
mHasShowGuide = true
}, 5)
}
}
} }
override fun onPause() { override fun onPause() {
@ -113,13 +301,50 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
} }
private fun showInterstitialAd(callback: () -> Unit) {
if (TestingManager.instance().isNormalAdDisable()) {
return
}
lifecycleScope.launch {
try {
when (val result = AdShowExt.showInterstitialAd(requireActivity(), "RV_VideoStream")) {
is AdResult.Success -> {
callback.invoke()
}
is AdResult.Failure -> {
callback.invoke()
}
AdResult.Loading -> {
}
}
} catch (e: Exception) {
callback.invoke()
}
}
}
private fun handleShouldShowAdDialog() {
val adDialog = WatchAdDialog(requireActivity(), VidiConst.WATCH_AD_FOR_WATCHED_3_VIDEOS,
WatchAdDialog.FROM_WATCH_5VIDEOS,null)
adDialog.setOnCloseListener {
showInterstitialAd {}
}
adDialog.show()
}
private fun setHomeTabStyle(f: Fragment?) { private fun setHomeTabStyle(f: Fragment?) {
isBackgroundBright = f.asSafe<OnFragmentBackgroundListener>()?.isBackgroundBright ?: return /*isBackgroundBright = f.asSafe<OnFragmentBackgroundListener>()?.isBackgroundBright ?: return
activity.asSafe<OnTabStyleListener>()?.onTabIsDarkFont(isBackgroundBright) activity.asSafe<OnTabStyleListener>()?.onTabIsDarkFont(isBackgroundBright)*/
} }
companion object { companion object {
const val VIDEO_NUM_GAP_FOR_AD_WATCHED = 3
const val VIDEO_NUM_GAP_FOR_AD_SWIPED = 5
internal fun newInstance() = HomeFragment() internal fun newInstance() = HomeFragment()
} }

View File

@ -2,21 +2,26 @@ package com.gamedog.vididin.main.fragments
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.ama.core.architecture.appBase.AppViewsFragment import com.ama.core.architecture.appBase.AppViewsFragment
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
import com.ama.core.architecture.util.AndroidUtil
import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.util.setOnClickBatch
import com.ama.core.architecture.util.setStatusBarDarkFont import com.ama.core.architecture.util.setStatusBarDarkFont
import com.ama.core.common.util.dp import com.ama.core.common.util.dp
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.router.Router import com.gamedog.vididin.router.Router
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue import kotlin.getValue
import com.gamedog.vididin.databinding.VididinappFeatureMineFragmentMineBinding as ViewBinding import com.viddin.videos.free.databinding.VididinappFeatureMineFragmentMineBinding as ViewBinding
import com.gamedog.vididin.main.fragments.mine.MineUiState as UiState import com.gamedog.vididin.main.fragments.mine.MineUiState as UiState
import com.gamedog.vididin.main.fragments.mine.MineViewModel as ViewModel import com.gamedog.vididin.main.fragments.mine.MineViewModel as ViewModel
@ -28,9 +33,6 @@ class MineFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(),
OnFragmentBackgroundListener { OnFragmentBackgroundListener {
override val mViewModel: ViewModel by viewModels() override val mViewModel: ViewModel by viewModels()
override var isBackgroundBright: Boolean = true override var isBackgroundBright: Boolean = true
private var isStatusBarDarkFont = false private var isStatusBarDarkFont = false
override fun inflateViewBinding( override fun inflateViewBinding(
@ -48,7 +50,7 @@ class MineFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(),
} }
override fun ViewBinding.initViews() { override fun ViewBinding.initViews() {
setOnClickBatch(rlPrivacy, rlVersion, rlFeedback) { setOnClickBatch(rlPrivacy, rlVersion, rlFeedback, ivEditName, ivSaveName) {
when (this) { when (this) {
rlPrivacy -> { rlPrivacy -> {
Router.Privacy.startActivity(requireActivity()) Router.Privacy.startActivity(requireActivity())
@ -59,6 +61,65 @@ class MineFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(),
rlFeedback -> { rlFeedback -> {
Router.Feedback.startActivity(requireActivity()) Router.Feedback.startActivity(requireActivity())
} }
ivEditName -> {
switchNameEditState(true)
}
ivSaveName -> {
switchNameEditState(false)
AndroidUtil.hideKeyboard(ivSaveName)
}
}
}
nameEditRoot.isVisible = false
nameNormalRoot.isVisible = true
var name = AccountManager.getAccount().userName
if (name.isEmpty()) {
name = "Miguel"
AccountManager.updateUserName(name)
}
tvAccountName.text = name
etAccountName.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
tvNameCharactCount.setText("(${s?.length}/15)")
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(
s: CharSequence?,
start: Int,
before: Int,
count: Int
) {
}
})
}
private fun switchNameEditState(isEnterEdit: Boolean) {
binding?.let {
with(it) {
nameEditRoot.isVisible = isEnterEdit
nameNormalRoot.isVisible = !isEnterEdit
if (isEnterEdit) {
etAccountName.setText(tvAccountName.text.toString().trim())
} else {
val newName = etAccountName.text.toString().trim()
if (newName.isNotEmpty()) {
tvAccountName.setText(newName)
AccountManager.updateUserName(newName)
}
}
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More