feat: WebView/媒体/红包详情全量实现 (#25~#30)

#25 MiniAppWebViewPage + MiniAppRouter
  - webview_flutter 加载 {apiBaseUrl}/miniapp/{appId}/index.html?gameId=...&token=...
  - MiniAppFloatButton 接收 chatId/chatType,默认打开 WebView
  - BannerState 新增 appId 字段,由 GameBannerData.appId 填充

#26 open_filex 文件打开
  - FileMessageBubble 下载完成后调用 OpenFilex.open(localPath)
  - 打开失败时 SnackBar 提示

#27 audioplayers 音频播放
  - AudioPlaybackService(Notifier):单例 AudioPlayer,togglePlay/pause/seek
  - AudioMessageBubble 接入:播放态图标切换、进度 mm:ss 显示

#28 video_player + chewie 视频全屏
  - VideoPlayerPage:本地文件 / HTTP 双模,chewie 控制栏
  - VideoMessageBubble 默认 onTap → push VideoPlayerPage

#29 红包领取排行榜详情页
  - GET /payment/rp/detail → RpDetailData + RpRecordItem DTO
  - GetRpDetailUseCase + getRpDetailUseCaseProvider
  - RedEnvelopeDetailSheet:汇总行 + 领取排行列表,头像/昵称/金额/时间

#30 MINE_RP 地雷红包发包 UI
  - _RpType 新增 mine(MINE_RP),显示地雷金额输入框
  - SendRpRequest.parameters 携带 mineAmount
  - RedEnvelopeBubble:非活跃状态直接打开详情,活跃状态领取后打开排行榜

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
pp-bot
2026-03-24 12:53:55 +09:00
parent e715a0673b
commit 23fc6b0c86
17 changed files with 1068 additions and 59 deletions

View File

@@ -0,0 +1,27 @@
import 'package:networks_sdk/networks_sdk.dart';
import 'package:im_app/data/remote/red_envelope_request.dart';
/// 获取红包领取详情 UseCase
///
/// 对应 Gitea issue #29 / iOS RedEnvelopeDetailSheet 领取排行榜数据源
///
/// ## 使用
///
/// ```dart
/// final detail = await ref.read(getRpDetailUseCaseProvider)
/// .execute(rpId: parsedContent['id']);
/// ```
class GetRpDetailUseCase {
final NetworksSdkApi _api;
const GetRpDetailUseCase({required NetworksSdkApi api}) : _api = api;
Future<RpDetailData> execute({required String rpId}) async {
final result = await _api.executeRequest(
GetRpDetailRequest(rpId: rpId),
);
if (result == null) throw Exception('获取红包详情失败');
return result;
}
}

View File

@@ -26,10 +26,11 @@ class SendRedEnvelopeUseCase {
/// [chatId] 会话 ID
/// [chatType] 1=私聊 / 2=群聊
/// [workspaceId] 群 workspaceId0 表示非工作台群)
/// [rpType] "STANDARD_RP" | "LUCKY_RP"(初期支持,后续扩展 MINE_RP / NN_RP
/// [rpType] "STANDARD_RP" | "LUCKY_RP" | "MINE_RP"NN_RP 由游戏自动触发
/// [amount] 总金额字符串,如 "10.00"
/// [rpNum] 红包数量
/// [remark] 红包祝福语
/// [mineAmount] 地雷金额(仅 MINE_RP 时传入,如 "5.00"
Future<String> execute({
required int chatId,
required int chatType,
@@ -38,6 +39,7 @@ class SendRedEnvelopeUseCase {
required String amount,
required int rpNum,
required String remark,
String? mineAmount,
}) async {
// #19 fix: 根据 workspaceId 动态决定 currencyType
final currencyType = await _resolveCurrencyType(workspaceId);
@@ -53,6 +55,7 @@ class SendRedEnvelopeUseCase {
rpNum: rpNum,
remark: remark,
msgSendTime: DateTime.now().microsecondsSinceEpoch,
mineAmount: mineAmount,
),
);