上下麦/表情 bug
This commit is contained in:
parent
6db3aa5ae8
commit
39464469ba
@ -68,7 +68,6 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
|||||||
"LUCKY_GIFT",
|
"LUCKY_GIFT",
|
||||||
"CP",
|
"CP",
|
||||||
"MAGIC",
|
"MAGIC",
|
||||||
"CUSTOMIZED",
|
|
||||||
"NSCIONAL_FLAG",
|
"NSCIONAL_FLAG",
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -212,7 +211,10 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
rtcProvider = Provider.of<RtcProvider>(context, listen: false);
|
rtcProvider = Provider.of<RtcProvider>(context, listen: false);
|
||||||
Provider.of<SCAppGeneralManager>(context, listen: false).giftList();
|
Provider.of<SCAppGeneralManager>(
|
||||||
|
context,
|
||||||
|
listen: false,
|
||||||
|
).giftList(includeCustomized: false);
|
||||||
Provider.of<SCAppGeneralManager>(context, listen: false).giftActivityList();
|
Provider.of<SCAppGeneralManager>(context, listen: false).giftActivityList();
|
||||||
// Provider.of<GeneralProvider>(context, listen: false).giftBackpack();
|
// Provider.of<GeneralProvider>(context, listen: false).giftBackpack();
|
||||||
Provider.of<SocialChatUserProfileManager>(context, listen: false).balance();
|
Provider.of<SocialChatUserProfileManager>(context, listen: false).balance();
|
||||||
@ -263,6 +265,7 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
|||||||
final availableTypes =
|
final availableTypes =
|
||||||
ref.giftByTab.entries
|
ref.giftByTab.entries
|
||||||
.where((entry) => entry.value.isNotEmpty)
|
.where((entry) => entry.value.isNotEmpty)
|
||||||
|
.where((entry) => entry.key != "CUSTOMIZED")
|
||||||
.map((entry) => entry.key)
|
.map((entry) => entry.key)
|
||||||
.toList();
|
.toList();
|
||||||
final orderedTypes = <String>[];
|
final orderedTypes = <String>[];
|
||||||
|
|||||||
@ -14,8 +14,6 @@ import 'package:yumi/app_localizations.dart';
|
|||||||
import 'package:yumi/app/config/business_logic_strategy.dart';
|
import 'package:yumi/app/config/business_logic_strategy.dart';
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
||||||
|
|
||||||
import '../../shared/data_sources/models/enum/sc_gift_type.dart';
|
|
||||||
|
|
||||||
enum _GiftGridPageStatus { idle, loading, ready }
|
enum _GiftGridPageStatus { idle, loading, ready }
|
||||||
|
|
||||||
const Duration _kGiftPageSkeletonMinDuration = Duration(milliseconds: 420);
|
const Duration _kGiftPageSkeletonMinDuration = Duration(milliseconds: 420);
|
||||||
@ -405,113 +403,63 @@ class _GiftTabPageState extends State<GiftTabPage>
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
: GestureDetector(
|
: GestureDetector(
|
||||||
child: Stack(
|
child: Container(
|
||||||
children: [
|
decoration: BoxDecoration(
|
||||||
Container(
|
borderRadius: BorderRadius.circular(12.w),
|
||||||
decoration: BoxDecoration(
|
color: Colors.white10,
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
border: Border.all(
|
||||||
color: Colors.white10,
|
color:
|
||||||
border: Border.all(
|
checkedIndex == ref.giftByTab[widget.type]!.indexOf(gift)
|
||||||
color:
|
? SocialChatTheme.primaryLight
|
||||||
checkedIndex ==
|
: Colors.transparent,
|
||||||
ref.giftByTab[widget.type]!.indexOf(gift)
|
width: 1.w,
|
||||||
? SocialChatTheme.primaryLight
|
),
|
||||||
: Colors.transparent,
|
),
|
||||||
width: 1.w,
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
netImage(
|
||||||
|
url: gift.giftPhoto ?? "",
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
width: 48.w,
|
||||||
|
height: 48.w,
|
||||||
|
loadingWidget: _buildGiftCoverLoading(),
|
||||||
|
errorWidget: _buildGiftCoverNoData(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5.w),
|
||||||
|
Container(
|
||||||
|
height: 23.w,
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 3.w),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: text(
|
||||||
|
gift.giftName ?? "",
|
||||||
|
maxLines: 2,
|
||||||
|
fontSize: 10.sp,
|
||||||
|
letterSpacing: 0.1,
|
||||||
|
lineHeight: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
textColor: widget.isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
netImage(
|
Image.asset(
|
||||||
url: gift.giftPhoto ?? "",
|
_strategy.getGiftPageGoldCoinIcon(),
|
||||||
fit: BoxFit.cover,
|
width: 14.w,
|
||||||
width: 48.w,
|
height: 14.w,
|
||||||
height: 48.w,
|
|
||||||
loadingWidget: _buildGiftCoverLoading(),
|
|
||||||
errorWidget: _buildGiftCoverNoData(),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 5.w),
|
SizedBox(width: 3.w),
|
||||||
Container(
|
text(
|
||||||
height: 23.w,
|
"${gift.giftCandy}",
|
||||||
margin: EdgeInsets.symmetric(horizontal: 3.w),
|
fontSize: 10.sp,
|
||||||
alignment: Alignment.center,
|
textColor: widget.isDark ? Colors.white : Colors.black,
|
||||||
child: text(
|
|
||||||
gift.giftName ?? "",
|
|
||||||
maxLines: 2,
|
|
||||||
fontSize: 10.sp,
|
|
||||||
letterSpacing: 0.1,
|
|
||||||
lineHeight: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
textColor: widget.isDark ? Colors.white : Colors.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Image.asset(
|
|
||||||
_strategy.getGiftPageGoldCoinIcon(),
|
|
||||||
width: 14.w,
|
|
||||||
height: 14.w,
|
|
||||||
),
|
|
||||||
SizedBox(width: 3.w),
|
|
||||||
text(
|
|
||||||
"${gift.giftCandy}",
|
|
||||||
fontSize: 10.sp,
|
|
||||||
textColor:
|
|
||||||
widget.isDark ? Colors.white : Colors.black,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
Positioned(
|
),
|
||||||
right: 3.w,
|
|
||||||
child: Column(
|
|
||||||
spacing: 3.w,
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 3.w),
|
|
||||||
// 只添加需要的 widget
|
|
||||||
if (scGiftHasFullScreenEffect(gift.special))
|
|
||||||
Image.asset(
|
|
||||||
_strategy.getGiftPageGiftEffectIcon(
|
|
||||||
SCGiftType.ANIMSCION.name,
|
|
||||||
),
|
|
||||||
width: 16.w,
|
|
||||||
height: 16.w,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
if (gift.special!.contains(SCGiftType.MUSIC.name))
|
|
||||||
Image.asset(
|
|
||||||
_strategy.getGiftPageGiftMusicIcon(
|
|
||||||
SCGiftType.MUSIC.name,
|
|
||||||
),
|
|
||||||
width: 16.w,
|
|
||||||
height: 16.w,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
if (gift.giftTab == (SCGiftType.LUCKY_GIFT.name))
|
|
||||||
Image.asset(
|
|
||||||
_strategy.getGiftPageGiftLuckIcon(
|
|
||||||
SCGiftType.LUCKY_GIFT.name,
|
|
||||||
),
|
|
||||||
width: 16.w,
|
|
||||||
height: 16.w,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
if (gift.giftTab == (SCGiftType.CP.name))
|
|
||||||
Image.asset(
|
|
||||||
_strategy.getGiftPageGiftCpIcon(SCGiftType.CP.name),
|
|
||||||
width: 16.w,
|
|
||||||
height: 16.w,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import 'package:yumi/app/constants/sc_room_msg_type.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:yumi/app/constants/sc_screen.dart';
|
import 'package:yumi/app/constants/sc_screen.dart';
|
||||||
import 'package:yumi/shared/tools/sc_path_utils.dart';
|
import 'package:yumi/shared/tools/sc_path_utils.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/mic_res.dart';
|
|
||||||
import 'package:yumi/services/audio/rtc_manager.dart';
|
import 'package:yumi/services/audio/rtc_manager.dart';
|
||||||
import 'package:yumi/shared/data_sources/models/enum/sc_room_special_mike_type.dart';
|
import 'package:yumi/shared/data_sources/models/enum/sc_room_special_mike_type.dart';
|
||||||
|
|
||||||
@ -313,15 +312,18 @@ class _SeatRenderSnapshot {
|
|||||||
|
|
||||||
class _SeatEmojiSnapshot {
|
class _SeatEmojiSnapshot {
|
||||||
const _SeatEmojiSnapshot({
|
const _SeatEmojiSnapshot({
|
||||||
|
required this.eventVersion,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.emojiPath,
|
required this.emojiPath,
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.number,
|
required this.number,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory _SeatEmojiSnapshot.fromMic(MicRes? mic) {
|
factory _SeatEmojiSnapshot.fromProvider(RtcProvider provider, num index) {
|
||||||
|
final mic = provider.micAtIndexForDisplay(index);
|
||||||
final emojiPath = mic?.emojiPath ?? "";
|
final emojiPath = mic?.emojiPath ?? "";
|
||||||
return _SeatEmojiSnapshot(
|
return _SeatEmojiSnapshot(
|
||||||
|
eventVersion: provider.emojiEventVersionForSeat(index),
|
||||||
userId: mic?.user?.id ?? "",
|
userId: mic?.user?.id ?? "",
|
||||||
emojiPath: emojiPath.isEmpty ? null : emojiPath,
|
emojiPath: emojiPath.isEmpty ? null : emojiPath,
|
||||||
type: mic?.type ?? "",
|
type: mic?.type ?? "",
|
||||||
@ -329,6 +331,7 @@ class _SeatEmojiSnapshot {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int eventVersion;
|
||||||
final String userId;
|
final String userId;
|
||||||
final String? emojiPath;
|
final String? emojiPath;
|
||||||
final String type;
|
final String type;
|
||||||
@ -342,6 +345,7 @@ class _SeatEmojiSnapshot {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return other is _SeatEmojiSnapshot &&
|
return other is _SeatEmojiSnapshot &&
|
||||||
|
other.eventVersion == eventVersion &&
|
||||||
other.userId == userId &&
|
other.userId == userId &&
|
||||||
other.emojiPath == emojiPath &&
|
other.emojiPath == emojiPath &&
|
||||||
other.type == type &&
|
other.type == type &&
|
||||||
@ -349,7 +353,8 @@ class _SeatEmojiSnapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(userId, emojiPath, type, number);
|
int get hashCode =>
|
||||||
|
Object.hash(eventVersion, userId, emojiPath, type, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SeatEmojiEvent {
|
class _SeatEmojiEvent {
|
||||||
@ -404,13 +409,18 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
emoticonsAniCtr.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Selector<RtcProvider, _SeatEmojiSnapshot>(
|
return Selector<RtcProvider, _SeatEmojiSnapshot>(
|
||||||
selector:
|
selector:
|
||||||
(context, provider) => _SeatEmojiSnapshot.fromMic(
|
(context, provider) =>
|
||||||
provider.micAtIndexForDisplay(widget.index),
|
_SeatEmojiSnapshot.fromProvider(provider, widget.index),
|
||||||
),
|
|
||||||
builder: (
|
builder: (
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
_SeatEmojiSnapshot snapshot,
|
_SeatEmojiSnapshot snapshot,
|
||||||
@ -423,8 +433,10 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
pathList.add(
|
pathList.add(
|
||||||
_SeatEmojiEvent(type: snapshot.type, number: snapshot.number),
|
_SeatEmojiEvent(type: snapshot.type, number: snapshot.number),
|
||||||
);
|
);
|
||||||
context.read<RtcProvider>().roomWheatMap[widget.index]?.setEmojiPath =
|
context.read<RtcProvider>().consumeSeatEmojiEvent(
|
||||||
null;
|
widget.index,
|
||||||
|
snapshot.eventVersion,
|
||||||
|
);
|
||||||
_checkStart();
|
_checkStart();
|
||||||
}
|
}
|
||||||
if (playingEvent != null) {
|
if (playingEvent != null) {
|
||||||
@ -518,6 +530,9 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
pathList.removeAt(0);
|
pathList.removeAt(0);
|
||||||
emoticonsAniCtr.forward();
|
emoticonsAniCtr.forward();
|
||||||
Future.delayed(Duration(milliseconds: 5)).then((value) {
|
Future.delayed(Duration(milliseconds: 5)).then((value) {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
showIn = true;
|
showIn = true;
|
||||||
});
|
});
|
||||||
@ -525,6 +540,9 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
/// 延迟3秒移除表情包
|
/// 延迟3秒移除表情包
|
||||||
Future.delayed(Duration(seconds: 3)).then((value) {
|
Future.delayed(Duration(seconds: 3)).then((value) {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
emoticonsAniCtr.reverse();
|
emoticonsAniCtr.reverse();
|
||||||
showIn = false;
|
showIn = false;
|
||||||
playingEvent = null;
|
playingEvent = null;
|
||||||
@ -535,6 +553,9 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
giftList.removeAt(0);
|
giftList.removeAt(0);
|
||||||
emoticonsAniCtr.forward();
|
emoticonsAniCtr.forward();
|
||||||
Future.delayed(Duration(milliseconds: 10)).then((value) {
|
Future.delayed(Duration(milliseconds: 10)).then((value) {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
showIn = true;
|
showIn = true;
|
||||||
});
|
});
|
||||||
@ -542,6 +563,9 @@ class _EmoticonsState extends State<Emoticons> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
/// 延迟3秒移除表情包
|
/// 延迟3秒移除表情包
|
||||||
Future.delayed(Duration(seconds: 1)).then((value) {
|
Future.delayed(Duration(seconds: 1)).then((value) {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
emoticonsAniCtr.reverse();
|
emoticonsAniCtr.reverse();
|
||||||
showIn = false;
|
showIn = false;
|
||||||
giftPath = null;
|
giftPath = null;
|
||||||
|
|||||||
@ -71,9 +71,9 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
|||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.read<RtcProvider>().requestMicrophoneListRefresh(
|
final rtcProvider = context.read<RtcProvider>();
|
||||||
notifyIfUnchanged: true,
|
rtcProvider.requestMicrophoneListRefresh(notifyIfUnchanged: true);
|
||||||
);
|
rtcProvider.fetchOnlineUsersList(notifyIfUnchanged: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
_subscription = eventBus.on<SCGiveRoomLuckPageDisposeEvent>().listen((
|
_subscription = eventBus.on<SCGiveRoomLuckPageDisposeEvent>().listen((
|
||||||
|
|||||||
@ -224,12 +224,6 @@ class _MePage2State extends State<MePage2> {
|
|||||||
iconPath: 'sc_images/index/sc_icon_bag.png',
|
iconPath: 'sc_images/index/sc_icon_bag.png',
|
||||||
onTap: () => SCNavigatorUtils.push(context, StoreRoute.bags),
|
onTap: () => SCNavigatorUtils.push(context, StoreRoute.bags),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10.w),
|
|
||||||
_buildEntryItem(
|
|
||||||
title: SCAppLocalizations.of(context)!.level,
|
|
||||||
iconPath: 'sc_images/index/sc_icon_level.png',
|
|
||||||
onTap: () => SCNavigatorUtils.push(context, SCMainRoute.levelList),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,6 +65,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
bool _disableOnlineUsersRefreshForCurrentSession = false;
|
bool _disableOnlineUsersRefreshForCurrentSession = false;
|
||||||
bool _isSelfMicActionInFlight = false;
|
bool _isSelfMicActionInFlight = false;
|
||||||
bool _pendingMicListRefresh = false;
|
bool _pendingMicListRefresh = false;
|
||||||
|
bool _pendingMicListRefreshNotifyIfUnchanged = false;
|
||||||
Timer? _deferredMicListRefreshTimer;
|
Timer? _deferredMicListRefreshTimer;
|
||||||
int _lastMicListRefreshStartedAtMs = 0;
|
int _lastMicListRefreshStartedAtMs = 0;
|
||||||
num? _preferredSelfMicIndex;
|
num? _preferredSelfMicIndex;
|
||||||
@ -86,6 +87,8 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
|
|
||||||
///麦位
|
///麦位
|
||||||
Map<num, MicRes> roomWheatMap = {};
|
Map<num, MicRes> roomWheatMap = {};
|
||||||
|
final Map<num, int> _seatEmojiEventVersions = {};
|
||||||
|
int _emojiPlaybackEventVersion = 0;
|
||||||
|
|
||||||
RtcEngine? engine;
|
RtcEngine? engine;
|
||||||
RtcEngineEventHandler? _rtcEngineEventHandler;
|
RtcEngineEventHandler? _rtcEngineEventHandler;
|
||||||
@ -375,6 +378,18 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
return seat?.copyWith(clearUser: true);
|
return seat?.copyWith(clearUser: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int emojiEventVersionForSeat(num index) {
|
||||||
|
return _seatEmojiEventVersions[index] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consumeSeatEmojiEvent(num index, int eventVersion) {
|
||||||
|
if (emojiEventVersionForSeat(index) != eventVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_seatEmojiEventVersions.remove(index);
|
||||||
|
roomWheatMap[index]?.setEmojiPath = null;
|
||||||
|
}
|
||||||
|
|
||||||
Map<num, MicRes> _stabilizeSelfMicSnapshot(
|
Map<num, MicRes> _stabilizeSelfMicSnapshot(
|
||||||
Map<num, MicRes> nextMap, {
|
Map<num, MicRes> nextMap, {
|
||||||
required Map<num, MicRes> previousMap,
|
required Map<num, MicRes> previousMap,
|
||||||
@ -1245,6 +1260,8 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
if (_isRefreshingMicList) {
|
if (_isRefreshingMicList) {
|
||||||
_pendingMicListRefresh = true;
|
_pendingMicListRefresh = true;
|
||||||
|
_pendingMicListRefreshNotifyIfUnchanged =
|
||||||
|
_pendingMicListRefreshNotifyIfUnchanged || notifyIfUnchanged;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_isRefreshingMicList = true;
|
_isRefreshingMicList = true;
|
||||||
@ -1279,9 +1296,14 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
_isRefreshingMicList = false;
|
_isRefreshingMicList = false;
|
||||||
if (_pendingMicListRefresh) {
|
if (_pendingMicListRefresh) {
|
||||||
_pendingMicListRefresh = false;
|
_pendingMicListRefresh = false;
|
||||||
|
final pendingNotifyIfUnchanged =
|
||||||
|
_pendingMicListRefreshNotifyIfUnchanged;
|
||||||
|
_pendingMicListRefreshNotifyIfUnchanged = false;
|
||||||
unawaited(
|
unawaited(
|
||||||
Future<void>.microtask(
|
Future<void>.microtask(
|
||||||
() => retrieveMicrophoneList(notifyIfUnchanged: notifyIfUnchanged),
|
() => retrieveMicrophoneList(
|
||||||
|
notifyIfUnchanged: notifyIfUnchanged || pendingNotifyIfUnchanged,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1377,6 +1399,10 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
_disableMicListRefreshForCurrentSession = false;
|
_disableMicListRefreshForCurrentSession = false;
|
||||||
_disableOnlineUsersRefreshForCurrentSession = false;
|
_disableOnlineUsersRefreshForCurrentSession = false;
|
||||||
_isSelfMicActionInFlight = false;
|
_isSelfMicActionInFlight = false;
|
||||||
|
_pendingMicListRefresh = false;
|
||||||
|
_pendingMicListRefreshNotifyIfUnchanged = false;
|
||||||
|
_seatEmojiEventVersions.clear();
|
||||||
|
_emojiPlaybackEventVersion = 0;
|
||||||
roomRocketStatus = null;
|
roomRocketStatus = null;
|
||||||
rtmProvider
|
rtmProvider
|
||||||
?.onNewMessageListenerGroupMap["${currenRoom?.roomProfile?.roomProfile?.roomAccount}"] =
|
?.onNewMessageListenerGroupMap["${currenRoom?.roomProfile?.roomProfile?.roomAccount}"] =
|
||||||
@ -1513,8 +1539,10 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _refreshMicListSilently() {
|
void _refreshMicListSilently({bool notifyIfUnchanged = false}) {
|
||||||
retrieveMicrophoneList(notifyIfUnchanged: false).catchError((_) {});
|
retrieveMicrophoneList(
|
||||||
|
notifyIfUnchanged: notifyIfUnchanged,
|
||||||
|
).catchError((_) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearUserFromSeats(String? userId, {num? exceptIndex}) {
|
void _clearUserFromSeats(String? userId, {num? exceptIndex}) {
|
||||||
@ -1634,10 +1662,10 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
_refreshMicListSilently();
|
_refreshMicListSilently(notifyIfUnchanged: true);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (_isCancelledRequest(ex)) {
|
if (_isCancelledRequest(ex)) {
|
||||||
_refreshMicListSilently();
|
_refreshMicListSilently(notifyIfUnchanged: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SCTts.show('Failed to put on the microphone, ${_errorMessageFrom(ex)}');
|
SCTts.show('Failed to put on the microphone, ${_errorMessageFrom(ex)}');
|
||||||
@ -1684,7 +1712,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (_isCancelledRequest(ex)) {
|
if (_isCancelledRequest(ex)) {
|
||||||
_refreshMicListSilently();
|
_refreshMicListSilently(notifyIfUnchanged: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SCTts.show('Failed to leave the microphone, ${_errorMessageFrom(ex)}');
|
SCTts.show('Failed to leave the microphone, ${_errorMessageFrom(ex)}');
|
||||||
@ -1998,16 +2026,20 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void starPlayEmoji(Msg msg) {
|
void starPlayEmoji(Msg msg) {
|
||||||
if (msg.number! > -1) {
|
final seatIndex = msg.number;
|
||||||
var mic = roomWheatMap[msg.number];
|
if (seatIndex == null || seatIndex < 0) {
|
||||||
if (mic != null && mic.user != null) {
|
return;
|
||||||
roomWheatMap[msg.number!] = mic.copyWith(
|
}
|
||||||
emojiPath: msg.msg,
|
var mic = roomWheatMap[seatIndex];
|
||||||
type: msg.type,
|
if (mic != null && mic.user != null) {
|
||||||
number: msg.msg,
|
_emojiPlaybackEventVersion += 1;
|
||||||
);
|
_seatEmojiEventVersions[seatIndex] = _emojiPlaybackEventVersion;
|
||||||
notifyListeners();
|
roomWheatMap[seatIndex] = mic.copyWith(
|
||||||
}
|
emojiPath: msg.msg,
|
||||||
|
type: msg.type,
|
||||||
|
number: msg.msg,
|
||||||
|
);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,12 +65,36 @@ class _RoomSeatWidgetState extends State<RoomSeatWidget> {
|
|||||||
return _normalizeSeatCount(count);
|
return _normalizeSeatCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _seatContentVersion(RtcProvider provider) {
|
||||||
|
var version = provider.roomWheatMap.length;
|
||||||
|
final micIndexes =
|
||||||
|
provider.roomWheatMap.keys.toList()..sort((a, b) => a.compareTo(b));
|
||||||
|
for (final micIndex in micIndexes) {
|
||||||
|
final seat = provider.micAtIndexForDisplay(micIndex);
|
||||||
|
final user = seat?.user;
|
||||||
|
version = Object.hash(
|
||||||
|
version,
|
||||||
|
micIndex,
|
||||||
|
seat?.micLock ?? false,
|
||||||
|
seat?.micMute ?? false,
|
||||||
|
user?.id ?? "",
|
||||||
|
user?.userAvatar ?? "",
|
||||||
|
user?.userNickname ?? "",
|
||||||
|
user?.roles ?? "",
|
||||||
|
user?.getHeaddress()?.sourceUrl ?? "",
|
||||||
|
user?.getVIP()?.name ?? "",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Selector<RtcProvider, _RoomSeatLayoutSnapshot>(
|
return Selector<RtcProvider, _RoomSeatLayoutSnapshot>(
|
||||||
selector:
|
selector:
|
||||||
(context, provider) => _RoomSeatLayoutSnapshot(
|
(context, provider) => _RoomSeatLayoutSnapshot(
|
||||||
seatCount: _seatCountFromMicIndexes(provider.roomWheatMap.keys),
|
seatCount: _seatCountFromMicIndexes(provider.roomWheatMap.keys),
|
||||||
|
seatContentVersion: _seatContentVersion(provider),
|
||||||
configuredSeatCount:
|
configuredSeatCount:
|
||||||
provider.currenRoom?.roomProfile?.roomSetting?.mikeSize
|
provider.currenRoom?.roomProfile?.roomSetting?.mikeSize
|
||||||
?.toInt() ??
|
?.toInt() ??
|
||||||
@ -233,12 +257,14 @@ class _RoomSeatWidgetState extends State<RoomSeatWidget> {
|
|||||||
class _RoomSeatLayoutSnapshot {
|
class _RoomSeatLayoutSnapshot {
|
||||||
const _RoomSeatLayoutSnapshot({
|
const _RoomSeatLayoutSnapshot({
|
||||||
required this.seatCount,
|
required this.seatCount,
|
||||||
|
required this.seatContentVersion,
|
||||||
required this.configuredSeatCount,
|
required this.configuredSeatCount,
|
||||||
required this.hasCurrentRoom,
|
required this.hasCurrentRoom,
|
||||||
required this.isExitingCurrentVoiceRoomSession,
|
required this.isExitingCurrentVoiceRoomSession,
|
||||||
});
|
});
|
||||||
|
|
||||||
final int seatCount;
|
final int seatCount;
|
||||||
|
final int seatContentVersion;
|
||||||
final int configuredSeatCount;
|
final int configuredSeatCount;
|
||||||
final bool hasCurrentRoom;
|
final bool hasCurrentRoom;
|
||||||
final bool isExitingCurrentVoiceRoomSession;
|
final bool isExitingCurrentVoiceRoomSession;
|
||||||
@ -250,6 +276,7 @@ class _RoomSeatLayoutSnapshot {
|
|||||||
}
|
}
|
||||||
return other is _RoomSeatLayoutSnapshot &&
|
return other is _RoomSeatLayoutSnapshot &&
|
||||||
other.seatCount == seatCount &&
|
other.seatCount == seatCount &&
|
||||||
|
other.seatContentVersion == seatContentVersion &&
|
||||||
other.configuredSeatCount == configuredSeatCount &&
|
other.configuredSeatCount == configuredSeatCount &&
|
||||||
other.hasCurrentRoom == hasCurrentRoom &&
|
other.hasCurrentRoom == hasCurrentRoom &&
|
||||||
other.isExitingCurrentVoiceRoomSession ==
|
other.isExitingCurrentVoiceRoomSession ==
|
||||||
@ -259,6 +286,7 @@ class _RoomSeatLayoutSnapshot {
|
|||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
seatCount,
|
seatCount,
|
||||||
|
seatContentVersion,
|
||||||
configuredSeatCount,
|
configuredSeatCount,
|
||||||
hasCurrentRoom,
|
hasCurrentRoom,
|
||||||
isExitingCurrentVoiceRoomSession,
|
isExitingCurrentVoiceRoomSession,
|
||||||
|
|||||||
@ -2,14 +2,46 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:yumi/app/constants/sc_room_msg_type.dart';
|
||||||
import 'package:yumi/modules/room/seat/sc_seat_item.dart';
|
import 'package:yumi/modules/room/seat/sc_seat_item.dart';
|
||||||
import 'package:yumi/services/audio/rtc_manager.dart';
|
import 'package:yumi/services/audio/rtc_manager.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/join_room_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/join_room_res.dart';
|
||||||
|
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/mic_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/mic_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/room_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/room_res.dart';
|
||||||
|
import 'package:yumi/ui_kit/widgets/room/room_msg_item.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/seat/room_seat_widget.dart';
|
import 'package:yumi/ui_kit/widgets/room/seat/room_seat_widget.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
test('starPlayEmoji creates a new event for repeated same emoji path', () {
|
||||||
|
final rtcProvider =
|
||||||
|
RealTimeCommunicationManager()
|
||||||
|
..roomWheatMap = {
|
||||||
|
1: MicRes(micIndex: 1, user: SocialChatUserProfile(id: 'user-1')),
|
||||||
|
};
|
||||||
|
final msg = Msg(
|
||||||
|
groupId: 'room-1',
|
||||||
|
msg: 'sc_images/room/emoji/fluent_emoji_01.webp',
|
||||||
|
type: SCRoomMsgType.emoticons,
|
||||||
|
number: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
rtcProvider.starPlayEmoji(msg);
|
||||||
|
final firstVersion = rtcProvider.emojiEventVersionForSeat(1);
|
||||||
|
|
||||||
|
expect(firstVersion, greaterThan(0));
|
||||||
|
expect(rtcProvider.roomWheatMap[1]?.emojiPath, msg.msg);
|
||||||
|
|
||||||
|
rtcProvider.consumeSeatEmojiEvent(1, firstVersion);
|
||||||
|
expect(rtcProvider.roomWheatMap[1]?.emojiPath, isNull);
|
||||||
|
|
||||||
|
rtcProvider.starPlayEmoji(msg);
|
||||||
|
final secondVersion = rtcProvider.emojiEventVersionForSeat(1);
|
||||||
|
|
||||||
|
expect(secondVersion, greaterThan(firstVersion));
|
||||||
|
expect(rtcProvider.roomWheatMap[1]?.emojiPath, msg.msg);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'RoomSeatWidget falls back to configured mikeSize when mic list is empty',
|
'RoomSeatWidget falls back to configured mikeSize when mic list is empty',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user