礼物gift以及谷歌service

This commit is contained in:
NIGGER SLAYER 2026-04-15 21:22:05 +08:00
parent 553c37c743
commit 73f1cf1199
8 changed files with 1534 additions and 1410 deletions

View File

@ -1,36 +1,20 @@
{ {
"project_info": { "project_info": {
"project_number": "980005024266", "project_number": "991697445884",
"project_id": "yumi-c3b30", "project_id": "yumi-chat-party",
"storage_bucket": "yumi-c3b30.firebasestorage.app" "storage_bucket": "yumi-chat-party.firebasestorage.app"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:980005024266:android:581aa38059aa318d9c65f3", "mobilesdk_app_id": "1:991697445884:android:1d6eff055324e2ba128879",
"android_client_info": { "android_client_info": {
"package_name": "com.org.yumiparty" "package_name": "com.org.yumiparty"
} }
}, },
"oauth_client": [ "oauth_client": [
{ {
"client_id": "980005024266-o9pjdmdbqqt1julbh1q1ovafcvmr1mv1.apps.googleusercontent.com", "client_id": "991697445884-6b6losu2td9u0era7qui4aeavm16lj57.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.org.yumiparty",
"certificate_hash": "3fe178dcc3294f7420df2754cfaf4646d6a19478"
}
},
{
"client_id": "980005024266-sl5h466pe90jsjmoi4jcd7bqhmckieec.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.org.yumiparty",
"certificate_hash": "9ab21924bfbe2c56555860ebabf23c4099fd7412"
}
},
{
"client_id": "980005024266-vrrp2us89svbqgc93oe7q4ad7uoh8fl6.apps.googleusercontent.com",
"client_type": 1, "client_type": 1,
"android_info": { "android_info": {
"package_name": "com.org.yumiparty", "package_name": "com.org.yumiparty",
@ -38,20 +22,28 @@
} }
}, },
{ {
"client_id": "980005024266-dgtthe3q98k8tk873rfdrsnu5ot61p09.apps.googleusercontent.com", "client_id": "991697445884-jc3r56gntpgdeicjj8j8qhkght67f7og.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.org.yumiparty",
"certificate_hash": "02a381c217fa1bd986cb00aefb8476efc5bea8e3"
}
},
{
"client_id": "991697445884-3ac3fk104691brjgkcejulijnivgr7o2.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
} }
], ],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyAbxU9QpbnC5PrrhUjDSK1camiotDlF3qE" "current_key": "AIzaSyDLY8LRCaKYapwXt2BvxUoHYD8kdC1fL70"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [ "other_platform_oauth_client": [
{ {
"client_id": "980005024266-dgtthe3q98k8tk873rfdrsnu5ot61p09.apps.googleusercontent.com", "client_id": "991697445884-3ac3fk104691brjgkcejulijnivgr7o2.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
} }
] ]
@ -60,4 +52,4 @@
} }
], ],
"configuration_version": "1" "configuration_version": "1"
} }

View File

@ -10,7 +10,6 @@ import 'package:provider/provider.dart';
/// ///
/// ///
class BaseBusinessLogicStrategy implements BusinessLogicStrategy { class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
List<Widget> getHomeTabPages(BuildContext context) { List<Widget> getHomeTabPages(BuildContext context) {
final List<Widget> pages = []; final List<Widget> pages = [];
@ -25,7 +24,6 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
return tabs; return tabs;
} }
@override @override
int getHomeInitialTabIndex() { int getHomeInitialTabIndex() {
return 0; return 0;
@ -33,7 +31,10 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
void onAvatarTap(BuildContext context) { void onAvatarTap(BuildContext context) {
Provider.of<SCAppGeneralManager>(context, listen: false).openDrawer(context); Provider.of<SCAppGeneralManager>(
context,
listen: false,
).openDrawer(context);
} }
@override @override
@ -125,11 +126,6 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
/// === === /// === ===
@override @override
bool shouldShowPasswordRoomIcon() { bool shouldShowPasswordRoomIcon() {
// //
@ -276,10 +272,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
const Color(0xFF3F0810), const Color(0xFF3F0810),
]; ];
} else { } else {
return [ return [const Color(0xFF666666), const Color(0xFF000000)];
const Color(0xFF666666),
const Color(0xFF000000),
];
} }
} }
@ -287,15 +280,9 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
List<Color> getMePageTabIndicatorGradient(bool isFemale) { List<Color> getMePageTabIndicatorGradient(bool isFemale) {
// Tab指示器渐变 // Tab指示器渐变
if (isFemale) { if (isFemale) {
return [ return [const Color(0xffC62548), const Color(0xff9C0322)];
const Color(0xffC62548),
const Color(0xff9C0322),
];
} else { } else {
return [ return [const Color(0xff141414), const Color(0xffE4E4E4)];
const Color(0xff141414),
const Color(0xffE4E4E4),
];
} }
} }
@ -446,10 +433,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
List<Color> getVipPageButtonGradient() { List<Color> getVipPageButtonGradient() {
// VIP按钮渐变颜色 // VIP按钮渐变颜色
return [ return [const Color(0xffFF5722), const Color(0xffFEB219)];
const Color(0xffFF5722),
const Color(0xffFEB219),
];
} }
@override @override
@ -519,7 +503,11 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
} }
@override @override
String getVipPagePreviewImage(int vipLevel, String previewType, String featureName) { String getVipPagePreviewImage(
int vipLevel,
String previewType,
String featureName,
) {
// VIP页面预览图像路径模式 // VIP页面预览图像路径模式
if (featureName == 'profile_frame') { if (featureName == 'profile_frame') {
return "sc_images/vip/sc_icon_vip${vipLevel}_profile_rev.png"; return "sc_images/vip/sc_icon_vip${vipLevel}_profile_rev.png";
@ -666,10 +654,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
List<Color> getAdminEditingButtonGradient(String buttonType) { List<Color> getAdminEditingButtonGradient(String buttonType) {
// 使 // 使
return [ return [const Color(0xffC670FF), const Color(0xff7726FF)];
const Color(0xffC670FF),
const Color(0xff7726FF),
];
} }
@override @override
@ -699,10 +684,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
return BoxDecoration( return BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all( border: Border.all(color: const Color(0xffE6E6E6), width: 1.0),
color: const Color(0xffE6E6E6),
width: 1.0,
),
); );
} }
@ -722,10 +704,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
Map<String, int> getAdminEditingViolationTypeMapping(String targetType) { Map<String, int> getAdminEditingViolationTypeMapping(String targetType) {
// ID映射 // ID映射
if (targetType == 'User') { if (targetType == 'User') {
return { return {'Pornography': 1, 'Illegal information': 2};
'Pornography': 1,
'Illegal information': 2,
};
} else if (targetType == 'Room') { } else if (targetType == 'Room') {
return { return {
'Pornography': 3, 'Pornography': 3,
@ -748,10 +727,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
List<Color> getAdminSearchButtonGradient(String pageType) { List<Color> getAdminSearchButtonGradient(String pageType) {
// - // -
return [ return [Colors.transparent, Colors.transparent];
Colors.transparent,
Colors.transparent,
];
} }
@override @override
@ -888,10 +864,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
@override @override
List<Color> getEditProfileGenderButtonGradient(bool isMale, bool isSelected) { List<Color> getEditProfileGenderButtonGradient(bool isMale, bool isSelected) {
// //
return [ return [const Color(0xffFF9326), const Color(0xffFEB219)];
const Color(0xffFF9326),
const Color(0xffFEB219),
];
} }
@override @override
@ -1203,11 +1176,14 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
case 'ACTIVITY': case 'ACTIVITY':
return "sc_images/room/sc_icon_activity_gift_head_bg.png"; return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'LUCK': case 'LUCK':
return "sc_images/room/sc_icon_luck_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'CP': case 'CP':
return "sc_images/room/sc_icon_cp_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'MAGIC': case 'MAGIC':
return "sc_images/room/sc_icon_magic_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
default: default:
return "sc_images/room/sc_icon_activity_gift_head_bg.png"; return "sc_images/room/sc_icon_activity_gift_head_bg.png";
} }
@ -1520,10 +1496,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
// Tab标签选中文本样式 // Tab标签选中文本样式
// 15"MyCustomFont" // 15"MyCustomFont"
// ScreenUtil().sp // ScreenUtil().sp
return const TextStyle( return const TextStyle(fontSize: 15, fontFamily: "MyCustomFont");
fontSize: 15,
fontFamily: "MyCustomFont",
);
} }
@override @override
@ -1531,10 +1504,7 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
// Tab标签未选中文本样式 // Tab标签未选中文本样式
// 13"MyCustomFont" // 13"MyCustomFont"
// ScreenUtil().sp // ScreenUtil().sp
return const TextStyle( return const TextStyle(fontSize: 13, fontFamily: "MyCustomFont");
fontSize: 13,
fontFamily: "MyCustomFont",
);
} }
@override @override
@ -1955,20 +1925,14 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
TextStyle getDynamicPageTabLabelStyle() { TextStyle getDynamicPageTabLabelStyle() {
// Tab标签选中文本样式 - TextStyle(fontWeight: FontWeight.bold, fontSize: 16.sp) // Tab标签选中文本样式 - TextStyle(fontWeight: FontWeight.bold, fontSize: 16.sp)
// 使.sp单位使ScreenUtil() // 使.sp单位使ScreenUtil()
return const TextStyle( return const TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
fontWeight: FontWeight.bold,
fontSize: 16,
);
} }
@override @override
TextStyle getDynamicPageTabUnselectedLabelStyle() { TextStyle getDynamicPageTabUnselectedLabelStyle() {
// Tab标签未选中文本样式 - TextStyle(fontWeight: FontWeight.normal, fontSize: 15.sp) // Tab标签未选中文本样式 - TextStyle(fontWeight: FontWeight.normal, fontSize: 15.sp)
// 使.sp单位使ScreenUtil() // 使.sp单位使ScreenUtil()
return const TextStyle( return const TextStyle(fontWeight: FontWeight.normal, fontSize: 15);
fontWeight: FontWeight.normal,
fontSize: 15,
);
} }
/// === === /// === ===
@ -2568,9 +2532,10 @@ class BaseBusinessLogicStrategy implements BusinessLogicStrategy {
// Scaffold背景颜色 - Colors.transparent // Scaffold背景颜色 - Colors.transparent
return Colors.transparent; return Colors.transparent;
} }
@override @override
Color getGoldRecordPageListBackgroundColor() { Color getGoldRecordPageListBackgroundColor() {
// - // -
return const Color(0xff1a1a1a); // #1a1a1a return const Color(0xff1a1a1a); // #1a1a1a
} }
} }

View File

@ -11,7 +11,6 @@ import '../../../modules/home/popular/party/sc_home_party_page.dart';
/// ///
/// ///
class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy { class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
/// Tab顺序 /// Tab顺序
@override @override
List<Widget> getHomeTabPages(BuildContext context) { List<Widget> getHomeTabPages(BuildContext context) {
@ -134,11 +133,6 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
/// === === /// === ===
@override @override
bool shouldShowPasswordRoomIcon() { bool shouldShowPasswordRoomIcon() {
// UI // UI
@ -1183,11 +1177,14 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
case 'ACTIVITY': case 'ACTIVITY':
return "sc_images/room/sc_icon_activity_gift_head_bg.png"; return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'LUCK': case 'LUCK':
return "sc_images/room/sc_icon_luck_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'CP': case 'CP':
return "sc_images/room/sc_icon_cp_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
case 'MAGIC': case 'MAGIC':
return "sc_images/room/sc_icon_magic_gift_head_bg.png"; // Fallback to the activity header until dedicated localized assets land.
return "sc_images/room/sc_icon_activity_gift_head_bg.png";
default: default:
return "sc_images/room/sc_icon_activity_gift_head_bg.png"; return "sc_images/room/sc_icon_activity_gift_head_bg.png";
} }
@ -1531,7 +1528,7 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getRechargePageScaffoldBackgroundColor() { Color getRechargePageScaffoldBackgroundColor() {
// Scaffold背景颜色 - // Scaffold背景颜色 -
return Colors.transparent; // #1a1a1a return Colors.transparent; // #1a1a1a
} }
@override @override
@ -1668,7 +1665,7 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getGoldRecordPageScaffoldBackgroundColor() { Color getGoldRecordPageScaffoldBackgroundColor() {
// Scaffold背景颜色 - // Scaffold背景颜色 -
return Colors.transparent; // #1a1a1a return Colors.transparent; // #1a1a1a
} }
@override @override
@ -1811,13 +1808,13 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getStoreItemUnselectedBorderColor() { Color getStoreItemUnselectedBorderColor() {
// Store商品项未选中边框颜色 - // Store商品项未选中边框颜色 -
return Colors.transparent; // Colors.black12 return Colors.transparent; // Colors.black12
} }
@override @override
Color getStoreItemSelectedBorderColor() { Color getStoreItemSelectedBorderColor() {
// Store商品项选中边框颜色 - 使 // Store商品项选中边框颜色 - 使
return SocialChatTheme.primaryLight; // Color(0xffFF9500) return SocialChatTheme.primaryLight; // Color(0xffFF9500)
} }
@override @override
@ -1829,7 +1826,7 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getStoreItemPriceTextColor() { Color getStoreItemPriceTextColor() {
// Store商品项价格文本颜色 - 使 // Store商品项价格文本颜色 - 使
return SocialChatTheme.primaryLight; // Colors.black return SocialChatTheme.primaryLight; // Colors.black
} }
@override @override
@ -2061,7 +2058,7 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getSearchPageScaffoldBackgroundColor() { Color getSearchPageScaffoldBackgroundColor() {
// Scaffold背景颜色 - 使 // Scaffold背景颜色 - 使
return Colors.transparent; // Colors.white return Colors.transparent; // Colors.white
} }
@override @override
@ -2436,7 +2433,7 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getSettingsPageContainerBorderColor() { Color getSettingsPageContainerBorderColor() {
// - 使 // - 使
return Colors.transparent; return Colors.transparent;
} }
@override @override
@ -2560,6 +2557,6 @@ class Variant1BusinessLogicStrategy extends BaseBusinessLogicStrategy {
@override @override
Color getGoldRecordPageListBackgroundColor() { Color getGoldRecordPageListBackgroundColor() {
// - // -
return Colors.transparent; // #1a1a1a return Colors.transparent; // #1a1a1a
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ const Duration _kGiftPageSkeletonMaxDuration = Duration(milliseconds: 900);
class GiftTabPage extends StatefulWidget { class GiftTabPage extends StatefulWidget {
final String type; final String type;
final bool isDark; final bool isDark;
final Function(int checkedIndex) checkedCall; final ValueChanged<SocialChatGiftRes?> checkedCall;
const GiftTabPage( const GiftTabPage(
this.type, this.type,
@ -53,13 +53,7 @@ class _GiftTabPageState extends State<GiftTabPage>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { checkedIndex = widget.type == "CUSTOMIZED" ? 1 : 0;
if (widget.type == "CUSTOMIZED") {
widget.checkedCall(1);
} else {
widget.checkedCall(0);
}
});
} }
@override @override
@ -522,7 +516,7 @@ class _GiftTabPageState extends State<GiftTabPage>
onTap: () { onTap: () {
setState(() { setState(() {
checkedIndex = ref.giftByTab[widget.type]!.indexOf(gift); checkedIndex = ref.giftByTab[widget.type]!.indexOf(gift);
widget.checkedCall(checkedIndex); widget.checkedCall(gift);
}); });
}, },
); );

View File

@ -109,13 +109,6 @@ class RealTimeCommunicationManager extends ChangeNotifier {
onError: (ErrorCodeType err, String msg) { onError: (ErrorCodeType err, String msg) {
print('rtc错误${err}'); print('rtc错误${err}');
}, },
onLocalAudioStateChanged:
(
RtcConnection connection,
LocalAudioStreamState state,
LocalAudioStreamReason reason,
) {},
onAudioRoutingChanged: (routing) {},
onAudioMixingStateChanged: ( onAudioMixingStateChanged: (
AudioMixingStateType state, AudioMixingStateType state,
AudioMixingReasonType reason, AudioMixingReasonType reason,
@ -132,15 +125,6 @@ class RealTimeCommunicationManager extends ChangeNotifier {
break; break;
} }
}, },
onRemoteAudioStateChanged: (
RtcConnection connection,
int remoteUid,
RemoteAudioState state,
RemoteAudioStateReason reason,
int elapsed,
) {
// print('用户 $remoteUid 音频状态: $state, 原因: $reason');
},
onJoinChannelSuccess: (RtcConnection connection, int elapsed) { onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
print('rtc 自己加入 ${connection.channelId} ${connection.localUid}'); print('rtc 自己加入 ${connection.channelId} ${connection.localUid}');
}, },
@ -1037,6 +1021,10 @@ class RealTimeCommunicationManager extends ChangeNotifier {
context!, context!,
listen: false, listen: false,
).engine?.setClientRole(role: ClientRoleType.clientRoleBroadcaster); ).engine?.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
Provider.of<RtcProvider>(
context!,
listen: false,
).engine?.muteLocalAudioStream(false);
} }
} }
} }

View File

@ -1,233 +1,214 @@
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/ui_kit/widgets/room/room_menu_dialog.dart';
import 'package:yumi/ui_kit/widgets/room/room_menu_dialog.dart'; import 'package:yumi/ui_kit/widgets/room/room_msg_input.dart';
import 'package:yumi/ui_kit/widgets/room/room_msg_input.dart'; import 'package:provider/provider.dart';
import 'package:provider/provider.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart';
import 'package:yumi/app_localizations.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart';
import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/services/audio/rtc_manager.dart';
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/modules/gift/gift_page.dart';
import 'package:yumi/services/audio/rtc_manager.dart';
import 'package:yumi/modules/gift/gift_page.dart'; import '../../../app/routes/sc_fluro_navigator.dart';
import '../../../modules/index/main_route.dart';
import '../../../app/routes/sc_fluro_navigator.dart'; import '../../../services/audio/rtm_manager.dart';
import '../../../modules/index/main_route.dart'; import '../../components/sc_debounce_widget.dart';
import '../../../services/audio/rtm_manager.dart';
import '../../components/sc_debounce_widget.dart'; class RoomBottomWidget extends StatefulWidget {
const RoomBottomWidget({super.key});
class RoomBottomWidget extends StatefulWidget {
@override @override
_RoomBottomWidgetState createState() => _RoomBottomWidgetState(); _RoomBottomWidgetState createState() => _RoomBottomWidgetState();
} }
class _RoomBottomWidgetState extends State<RoomBottomWidget> { class _RoomBottomWidgetState extends State<RoomBottomWidget> {
int roomMenuStime1 = 0; int roomMenuStime1 = 0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
Container( Container(
height: 55.w, height: 55.w,
margin: EdgeInsetsDirectional.only(start: 25.w), margin: EdgeInsetsDirectional.only(start: 25.w),
child: Row( child: Row(
children: [ children: [
SCDebounceWidget( SCDebounceWidget(
onTap: () { onTap: () {
if (SCRoomUtils.touristCanMsg(context)) { if (SCRoomUtils.touristCanMsg(context)) {
Navigator.push( Navigator.push(context, PopRoute(child: RoomMsgInput()));
context, }
PopRoute(child: RoomMsgInput()), },
); child: Image.asset(
} "sc_images/room/icon_room_input_t.png",
}, child: Image.asset( width: 30.w,
"sc_images/room/icon_room_input_t.png", height: 30.w,
width: 30.w, ),
height: 30.w, ),
), Spacer(),
), Consumer<RtcProvider>(
Spacer(), builder: (context, ref, child) {
Consumer<RtcProvider>( return _mic1(ref);
builder: (context, ref, child) { },
return _mic1(ref); ),
}, SizedBox(width: 10.w),
), SCDebounceWidget(
SizedBox(width: 10.w), child: Image.asset(
SCDebounceWidget( "sc_images/room/sc_icon_botton_menu.png",
child: Image.asset( width: 30.w,
"sc_images/room/sc_icon_botton_menu.png", height: 30.w,
width: 30.w, fit: BoxFit.contain,
height: 30.w, ),
fit: BoxFit.contain, onTap: () {
), SmartDialog.show(
onTap: () { tag: "showRoomMenuDialog",
SmartDialog.show( alignment: Alignment.bottomCenter,
tag: "showRoomMenuDialog", debounce: true,
alignment: Alignment.bottomCenter, animationType: SmartAnimationType.fade,
debounce: true, maskColor: Colors.transparent,
animationType: SmartAnimationType.fade, clickMaskDismiss: true,
maskColor: Colors.transparent, builder: (_) {
clickMaskDismiss: true, return RoomMenuDialog(roomMenuStime1, (eTime) {
builder: (_) { roomMenuStime1 = eTime;
return RoomMenuDialog(roomMenuStime1, (eTime) { });
roomMenuStime1 = eTime; },
}); );
}, },
); ),
}, SizedBox(width: 10.w),
), SCDebounceWidget(
SizedBox(width: 10.w), child: Selector<RtmProvider, int>(
SCDebounceWidget( selector: (c, p) => p.allUnReadCount,
child: Selector<RtmProvider, int>( shouldRebuild: (prev, next) => prev != next,
selector: (c, p) => p.allUnReadCount, builder: (_, allUnReadCount, __) {
shouldRebuild: (prev, next) => prev != next, return allUnReadCount > 0
builder: (_, allUnReadCount, __) { ? Badge(
return allUnReadCount > 0 backgroundColor: Colors.red,
? Badge( label: text(
backgroundColor: Colors.red, "${allUnReadCount > 99 ? "99+" : allUnReadCount}",
label: text( fontSize: 9.sp,
"${allUnReadCount > 99 ? "99+" : allUnReadCount}", textColor: Colors.white,
fontSize: 9.sp, fontWeight: FontWeight.w600,
textColor: Colors.white, ),
fontWeight: FontWeight.w600, alignment: AlignmentDirectional.topEnd,
), child: Image.asset(
alignment: AlignmentDirectional.topEnd, "sc_images/room/sc_icon_botton_message.png",
child: Image.asset( width: 30.w,
"sc_images/room/sc_icon_botton_message.png", height: 30.w,
width: 30.w, fit: BoxFit.contain,
height: 30.w, ),
fit: BoxFit.contain, )
), : Image.asset(
) "sc_images/room/sc_icon_botton_message.png",
: Image.asset( width: 30.w,
"sc_images/room/sc_icon_botton_message.png", height: 30.w,
width: 30.w, fit: BoxFit.contain,
height: 30.w, );
fit: BoxFit.contain, },
); ),
}, onTap: () {
), SCNavigatorUtils.push(
onTap: () { context,
SCNavigatorUtils.push( "${SCMainRoute.message}?isFromRoom=true",
context, );
"${SCMainRoute.message}?isFromRoom=true", },
); ),
}, SizedBox(width: 15.w),
), ],
SizedBox(width: 15.w), ),
], ),
), PositionedDirectional(
), bottom: 8.w,
PositionedDirectional( child: SCDebounceWidget(
bottom: 8.w, onTap: () {
child: SCDebounceWidget( SmartDialog.show(
onTap: () { tag: "showGiftControl",
SmartDialog.show( alignment: Alignment.bottomCenter,
tag: "showGiftControl", maskColor: Colors.transparent,
alignment: Alignment.bottomCenter, animationType: SmartAnimationType.fade,
maskColor: Colors.transparent, clickMaskDismiss: true,
animationType: SmartAnimationType.fade, builder: (_) {
clickMaskDismiss: true, return GiftPage();
builder: (_) { },
return GiftPage(); );
}, },
); child: Image.asset(
}, "sc_images/room/sc_icon_botton_gift.png",
child: Image.asset( width: 45.w,
"sc_images/room/sc_icon_botton_gift.png", height: 45.w,
width: 45.w, fit: BoxFit.contain,
height: 45.w, ),
fit: BoxFit.contain, ),
), ),
), ],
), );
], }
);
} _mic1(RtcProvider provider) {
///
_mic1(RtcProvider provider) { bool show = false;
///
bool show = false; ///
provider.roomWheatMap.forEach((k, v) {
/// if (v.user?.id == AccountStorage().getCurrentUser()?.userProfile?.id) {
provider.roomWheatMap.forEach((k, v) { show = true;
if (v.user?.id == AccountStorage().getCurrentUser()?.userProfile?.id) { }
show = true; });
}
}); return Visibility(
visible: show,
return Visibility( child: GestureDetector(
visible: show, behavior: HitTestBehavior.opaque,
child: GestureDetector( onTap: () {
behavior: HitTestBehavior.opaque, setState(() {
onTap: () { provider.isMic = !provider.isMic;
setState(() {
provider.isMic = !provider.isMic; ///
provider.roomWheatMap.forEach((k, v) {
/// if (v.user?.id ==
provider.roomWheatMap.forEach((k, v) { AccountStorage().getCurrentUser()?.userProfile?.id &&
if (v.user?.id == !provider.roomWheatMap[k]!.micMute!) {
AccountStorage().getCurrentUser()?.userProfile?.id && if (!provider.isMic) {
!provider.roomWheatMap[k]!.micMute!) { provider.engine?.adjustRecordingSignalVolume(100);
if (!provider.isMic) { provider.engine?.setClientRole(
Provider.of<RtcProvider>( role: ClientRoleType.clientRoleBroadcaster,
context, );
listen: false, provider.engine?.muteLocalAudioStream(false);
).engine?.adjustRecordingSignalVolume(100); } else {
Provider.of<RtcProvider>( if (provider.isMusicPlaying) {
context, provider.engine?.adjustRecordingSignalVolume(0);
listen: false, } else {
).engine?.setClientRole( provider.engine?.setClientRole(
role: ClientRoleType.clientRoleBroadcaster, role: ClientRoleType.clientRoleAudience,
); );
} else { provider.engine?.muteLocalAudioStream(provider.isMic);
if (Provider.of<RtcProvider>( }
context, }
listen: false, }
).isMusicPlaying) { });
Provider.of<RtcProvider>( });
context, },
listen: false, child: Padding(
).engine?.adjustRecordingSignalVolume(0); padding: EdgeInsets.only(right: 12.w),
} else { child: Container(
Provider.of<RtcProvider>( width: 30.w,
context, height: 30.w,
listen: false, alignment: Alignment.center,
).engine?.setClientRole( // decoration: BoxDecoration(
role: ClientRoleType.clientRoleAudience, // color: Colors.white.withOpacity(0.2), shape: BoxShape.circle
); // ),
Provider.of<RtcProvider>( child: Image.asset(
context, "sc_images/room/${provider.isMic ? 'sc_icon_botton_mic_close' : 'sc_icon_botton_mic_open'}.png",
listen: false, width: 30.w,
).engine?.muteLocalAudioStream(provider.isMic); fit: BoxFit.fill,
} gaplessPlayback: true,
} ),
} ),
}); ),
}); ),
}, );
child: Padding( }
padding: EdgeInsets.only(right: 12.w), }
child: Container(
width: 30.w,
height: 30.w,
alignment: Alignment.center,
// decoration: BoxDecoration(
// color: Colors.white.withOpacity(0.2), shape: BoxShape.circle
// ),
child: Image.asset(
"sc_images/room/${provider.isMic ? 'sc_icon_botton_mic_close' : 'sc_icon_botton_mic_open'}.png",
width: 30.w,
fit: BoxFit.fill,
gaplessPlayback: true,
),
),
),
),
);
}
}

View File

@ -13,6 +13,11 @@
- 本轮按需求暂未处理网络链路上的启动等待,例如审核态检查或远端启动页配置请求。 - 本轮按需求暂未处理网络链路上的启动等待,例如审核态检查或远端启动页配置请求。
## 已完成模块 ## 已完成模块
- 已排查语言房“双设备、不同账号进入同一房间,上麦后无声”的直接原因:当前 RTC 进房时统一以 Agora `Audience` 身份加入频道,见 `lib/services/audio/rtc_manager.dart``joinChannel()``clientRoleType: clientRoleAudience`;而本地麦克风开关 `isMic` 默认值为 `true`(当前语义实际是“闭麦”),上麦 `shangMai()` 后只有在 `!isMic` 时才会切到 `Broadcaster` 并取消本地静音,所以“只上麦、不点底部麦克风按钮”时不会发声。
- 已补充语言房当前真实交互结论:现有实现里“上麦”和“开麦”是两个动作。用户点空麦位后只是占麦;还需要再点击底部麦克风按钮,触发 `lib/ui_kit/widgets/room/room_bottom_widget.dart` 中的角色切换,才能真正开始向房间发送音频。
- 已同步补充该需求的后续决策点:如果产品预期是“上麦即能说话”,则需要单独改需求并调整实现为“上麦成功后自动切 `Broadcaster` 且自动开麦”;如果继续保留当前双步骤交互,则至少要补一条明确提示文案/引导,并把“双设备不同账号同房,上麦后需手动开麦才能互听”加入验收用例,避免测试误判为 RTC 故障。
- 已重新收敛语言房无声修复方案:撤回上一轮会影响进房的较大改动后,当前改为只做最小行为修补,不触碰进房和 token/join 链路;已在“底部麦克风点开”和“麦位解除静音且本人处于开麦态”两条路径上补齐 `muteLocalAudioStream(false)`,修正 UI 显示已开麦但 Agora 本地音频流仍保持静音的问题。
- 已按测试收尾要求移除语言房 RTC 诊断面板:该组件仅用于当前无声问题的真机排查,现已从房间页和相关临时诊断代码中整体删除,不作为正式功能保留。
- 已为语言房页面补充右下方 `game` 悬浮入口:入口位于聊天区右下侧、距右侧约 `15.w`、位于底部操作栏上方约 `100.w`,当前先使用代码绘制的 `🎮` 占位图标,并已在实现处标注后续替换为正式 UI 图片资源。 - 已为语言房页面补充右下方 `game` 悬浮入口:入口位于聊天区右下侧、距右侧约 `15.w`、位于底部操作栏上方约 `100.w`,当前先使用代码绘制的 `🎮` 占位图标,并已在实现处标注后续替换为正式 UI 图片资源。
- 已新增语言房游戏底部弹窗:点击 `game` 入口后会从底部弹出约三分之一屏高的面板,采用房间页现有半透明磨砂风格,便于后续继续沿用当前视觉体系。 - 已新增语言房游戏底部弹窗:点击 `game` 入口后会从底部弹出约三分之一屏高的面板,采用房间页现有半透明磨砂风格,便于后续继续沿用当前视觉体系。
- 已补齐语言房游戏列表占位结构:弹窗内部先用静态游戏数据驱动,并按“`ListView` 可上下滑动 + 每行 `5` 个图标位”的方式实现,后续只需替换入口图、列表图标和真实接口数据即可继续开发。 - 已补齐语言房游戏列表占位结构:弹窗内部先用静态游戏数据驱动,并按“`ListView` 可上下滑动 + 每行 `5` 个图标位”的方式实现,后续只需替换入口图、列表图标和真实接口数据即可继续开发。