1109 lines
36 KiB
Dart
1109 lines
36 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
import 'package:yumi/app_localizations.dart';
|
|
import 'package:yumi/main.dart';
|
|
import 'package:yumi/ui_kit/components/sc_debounce_widget.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/modules/index/main_route.dart';
|
|
import 'package:yumi/services/audio/rtm_manager.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/room_msg_input.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/room_user_card_setting.dart';
|
|
import 'package:yumi/ui_kit/widgets/badge/sc_user_badge_strip.dart';
|
|
import 'package:marquee/marquee.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
|
import 'package:tencent_cloud_chat_sdk/enum/conversation_type.dart';
|
|
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
|
|
import 'package:yumi/shared/tools/sc_lk_dialog_util.dart';
|
|
import 'package:yumi/shared/tools/sc_room_utils.dart';
|
|
import 'package:yumi/shared/data_sources/models/enum/sc_props_type.dart';
|
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart';
|
|
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
|
|
import 'package:yumi/shared/business_logic/models/res/room_user_card_res.dart'
|
|
as room_card;
|
|
import 'package:yumi/services/general/sc_app_general_manager.dart';
|
|
import 'package:yumi/services/audio/rtc_manager.dart';
|
|
import 'package:yumi/services/auth/user_profile_manager.dart';
|
|
import 'package:yumi/modules/gift/gift_page.dart';
|
|
import 'package:yumi/ui_kit/widgets/id/sc_special_id_badge.dart';
|
|
import 'package:yumi/ui_kit/widgets/props/sc_data_card_resource_view.dart';
|
|
|
|
import '../../../shared/data_sources/models/enum/sc_room_roles_type.dart';
|
|
import '../../../shared/business_logic/models/res/sc_user_identity_res.dart';
|
|
import '../../../modules/chat/chat_route.dart';
|
|
|
|
class RoomUserInfoCard extends StatefulWidget {
|
|
final String? userId;
|
|
|
|
const RoomUserInfoCard({super.key, this.userId});
|
|
|
|
@override
|
|
State<RoomUserInfoCard> createState() => _RoomUserInfoCardState();
|
|
}
|
|
|
|
class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
|
static const String _leaveMicActionIconAsset =
|
|
"sc_images/room/sc_icon_room_user_card_leave_mic.png";
|
|
static const String _defaultProfileCardBackgroundAsset =
|
|
"sc_images/room/sc_bg_room_user_profile_card_default.png";
|
|
static const double _profileSheetHeightFactor = 0.4;
|
|
static const double _dataCardTranslateDownFactor = 0.4;
|
|
static const double _defaultBackgroundImageFactor = 0.68;
|
|
|
|
SocialChatUserProfileManager? userProvider;
|
|
String roomId = "";
|
|
SCUserIdentityRes? userIdentity;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
userProvider = Provider.of<SocialChatUserProfileManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
roomId =
|
|
Provider.of<RtcProvider>(
|
|
context,
|
|
listen: false,
|
|
).currenRoom?.roomProfile?.roomProfile?.id ??
|
|
"";
|
|
userProvider?.roomUserCard(roomId, widget.userId ?? "");
|
|
SCAccountRepository().userIdentity(userId: widget.userId).then((v) {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
userIdentity = v;
|
|
setState(() {});
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
userProvider?.userCardInfo = null;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final sheetHeight =
|
|
MediaQuery.of(context).size.height * _profileSheetHeightFactor;
|
|
|
|
return Consumer<SocialChatUserProfileManager>(
|
|
builder: (context, ref, child) {
|
|
final currentUserId =
|
|
AccountStorage().getCurrentUser()?.userProfile?.id;
|
|
final isSelf = widget.userId == currentUserId;
|
|
final rtcProvider = Provider.of<RtcProvider>(context, listen: false);
|
|
final currentMicIndex =
|
|
isSelf && currentUserId != null
|
|
? rtcProvider.userOnMaiInIndex(currentUserId)
|
|
: -1;
|
|
final canLeaveMic = currentMicIndex > -1;
|
|
|
|
if (ref.userCardInfo == null) {
|
|
return _buildLoadingSheet(sheetHeight);
|
|
}
|
|
|
|
return _buildProfileSheet(
|
|
context: context,
|
|
ref: ref,
|
|
rtcProvider: rtcProvider,
|
|
sheetHeight: sheetHeight,
|
|
isSelf: isSelf,
|
|
currentMicIndex: currentMicIndex,
|
|
canLeaveMic: canLeaveMic,
|
|
currentUserId: currentUserId,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildLoadingSheet(double sheetHeight) {
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
height: sheetHeight,
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)),
|
|
child: Stack(
|
|
children: [
|
|
Positioned.fill(child: _buildDefaultSheetBackground()),
|
|
Center(
|
|
child: Container(
|
|
width: 55.w,
|
|
height: 55.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.black26,
|
|
borderRadius: BorderRadius.circular(8.w),
|
|
),
|
|
child: CupertinoActivityIndicator(color: Colors.white24),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProfileSheet({
|
|
required BuildContext context,
|
|
required SocialChatUserProfileManager ref,
|
|
required RtcProvider rtcProvider,
|
|
required double sheetHeight,
|
|
required bool isSelf,
|
|
required num currentMicIndex,
|
|
required bool canLeaveMic,
|
|
required String? currentUserId,
|
|
}) {
|
|
final bottomPadding = MediaQuery.of(context).padding.bottom;
|
|
final profile = ref.userCardInfo?.userProfile;
|
|
final dataCard = _activeDataCard(ref.userCardInfo);
|
|
final canShowReport = currentUserId != widget.userId;
|
|
final canShowSetting =
|
|
canShowReport &&
|
|
ref.userCardInfo?.roomRole != SCRoomRolesType.HOMEOWNER.name &&
|
|
(rtcProvider.isFz() || rtcProvider.isGL());
|
|
|
|
final profileContent = _buildProfileContentLayer(
|
|
context: context,
|
|
ref: ref,
|
|
rtcProvider: rtcProvider,
|
|
profile: profile,
|
|
bottomPadding: bottomPadding,
|
|
isSelf: isSelf,
|
|
canLeaveMic: canLeaveMic,
|
|
currentMicIndex: currentMicIndex,
|
|
canShowReport: canShowReport,
|
|
canShowSetting: canShowSetting,
|
|
);
|
|
|
|
if (dataCard == null) {
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
height: sheetHeight,
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)),
|
|
child: Stack(
|
|
children: [
|
|
Positioned.fill(child: _buildDefaultSheetBackground()),
|
|
Positioned.fill(child: profileContent),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return _buildDataCardFrame(
|
|
sheetHeight: sheetHeight,
|
|
dataCard: dataCard,
|
|
child: profileContent,
|
|
);
|
|
}
|
|
|
|
Widget _buildDataCardFrame({
|
|
required double sheetHeight,
|
|
required PropsResources dataCard,
|
|
required Widget child,
|
|
}) {
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
height: sheetHeight,
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Positioned.fill(
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)),
|
|
child: DecoratedBox(decoration: _sheetDecoration()),
|
|
),
|
|
),
|
|
Positioned(
|
|
left: 0,
|
|
right: 0,
|
|
top: sheetHeight * _dataCardTranslateDownFactor,
|
|
height: sheetHeight,
|
|
child: IgnorePointer(child: _buildSheetBackground(dataCard)),
|
|
),
|
|
Positioned.fill(
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)),
|
|
child: child,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProfileContentLayer({
|
|
required BuildContext context,
|
|
required SocialChatUserProfileManager ref,
|
|
required RtcProvider rtcProvider,
|
|
required SocialChatUserProfile? profile,
|
|
required double bottomPadding,
|
|
required bool isSelf,
|
|
required bool canLeaveMic,
|
|
required num currentMicIndex,
|
|
required bool canShowReport,
|
|
required bool canShowSetting,
|
|
}) {
|
|
return Stack(
|
|
children: [
|
|
Positioned.fill(
|
|
child: LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
return Align(
|
|
alignment: Alignment.topCenter,
|
|
child: FittedBox(
|
|
fit: BoxFit.scaleDown,
|
|
alignment: Alignment.topCenter,
|
|
child: SizedBox(
|
|
width: constraints.maxWidth,
|
|
child: Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
18.w,
|
|
10.w,
|
|
18.w,
|
|
bottomPadding > 6.w ? bottomPadding : 6.w,
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
_buildProfileHeader(context, profile, ref),
|
|
SizedBox(height: 6.w),
|
|
_buildBadgeStrip(
|
|
profile?.id ?? widget.userId,
|
|
ref,
|
|
profile,
|
|
),
|
|
SizedBox(height: 8.w),
|
|
_buildActions(
|
|
context: context,
|
|
ref: ref,
|
|
rtcProvider: rtcProvider,
|
|
isSelf: isSelf,
|
|
canLeaveMic: canLeaveMic,
|
|
currentMicIndex: currentMicIndex,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
if (canShowReport)
|
|
Positioned(
|
|
top: 14.w,
|
|
right: 16.w,
|
|
child: _buildHeaderIconButton(
|
|
iconAsset: "sc_images/room/sc_icon_user_card_report.png",
|
|
onTap: () {
|
|
final route =
|
|
"${SCMainRoute.report}?type=user&tageId=${widget.userId}";
|
|
Navigator.of(context).pop();
|
|
SCNavigatorUtils.push(
|
|
navigatorKey.currentState?.context ?? context,
|
|
route,
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
if (canShowSetting)
|
|
Positioned(
|
|
top: 14.w,
|
|
right: 52.w,
|
|
child: _buildHeaderIconButton(
|
|
iconAsset: "sc_images/room/sc_icon_room_user_card_setting.png",
|
|
onTap: () {
|
|
if (userProvider?.userCardInfo == null) {
|
|
return;
|
|
}
|
|
Navigator.of(context).pop();
|
|
showBottomInBottomDialog(
|
|
navigatorKey.currentState?.context ?? context,
|
|
RoomUserCardSetting(
|
|
roomId: roomId,
|
|
userCardInfo: userProvider?.userCardInfo?.copyWith(),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
BoxDecoration _sheetDecoration() {
|
|
return const BoxDecoration(color: Color(0xff061F1E));
|
|
}
|
|
|
|
Widget _buildDefaultSheetBackground() {
|
|
return DecoratedBox(
|
|
decoration: _sheetDecoration(),
|
|
child: Center(
|
|
child: FractionallySizedBox(
|
|
widthFactor: _defaultBackgroundImageFactor,
|
|
heightFactor: _defaultBackgroundImageFactor,
|
|
child: Image.asset(
|
|
_defaultProfileCardBackgroundAsset,
|
|
fit: BoxFit.contain,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSheetBackground(PropsResources? dataCard) {
|
|
if (dataCard == null) {
|
|
return _buildDefaultSheetBackground();
|
|
}
|
|
|
|
return SCDataCardResourceView(
|
|
resource: dataCard,
|
|
fit: BoxFit.cover,
|
|
showCoverFallback: false,
|
|
allowCoverAsResource: false,
|
|
);
|
|
}
|
|
|
|
PropsResources? _activeDataCard(room_card.RoomUserCardRes? cardInfo) {
|
|
return _activeDataCardFromUseProps(cardInfo?.userProfile?.useProps) ??
|
|
_activeDataCardFromUseProps(cardInfo?.useProps);
|
|
}
|
|
|
|
PropsResources? _activeDataCardFromUseProps(List<UseProps>? useProps) {
|
|
final now = DateTime.now().millisecondsSinceEpoch;
|
|
for (final item in useProps ?? const <UseProps>[]) {
|
|
final resource = item.propsResources;
|
|
if (resource?.type != SCPropsType.DATA_CARD.name) {
|
|
continue;
|
|
}
|
|
final expireText = item.expireTime?.trim() ?? "";
|
|
final expireTime = int.tryParse(expireText);
|
|
if (expireText.isNotEmpty && (expireTime ?? 0) <= now) {
|
|
continue;
|
|
}
|
|
final source = resource?.sourceUrl?.trim() ?? "";
|
|
final cover = resource?.cover?.trim() ?? "";
|
|
if (source.isNotEmpty || cover.isNotEmpty) {
|
|
return resource;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Widget _buildProfileHeader(
|
|
BuildContext context,
|
|
SocialChatUserProfile? profile,
|
|
SocialChatUserProfileManager ref,
|
|
) {
|
|
return Column(
|
|
children: [
|
|
GestureDetector(
|
|
onTap: () => _openProfile(context),
|
|
child: head(
|
|
url: profile?.userAvatar ?? "",
|
|
width: 105.w,
|
|
border: Border.all(color: Colors.white, width: 3),
|
|
headdress: profile?.getHeaddress()?.sourceUrl,
|
|
headdressCover: profile?.getHeaddress()?.cover,
|
|
),
|
|
),
|
|
SizedBox(height: 5.w),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
msgRoleTag(
|
|
ref.userCardInfo?.roomRole ?? "",
|
|
width: 16.w,
|
|
height: 16.w,
|
|
),
|
|
SizedBox(width: 4.w),
|
|
socialchatNickNameText(
|
|
maxWidth: 116.w,
|
|
profile?.userNickname ?? "",
|
|
fontSize: 18.sp,
|
|
textColor: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
type: "",
|
|
needScroll: (profile?.userNickname?.characters.length ?? 0) > 12,
|
|
),
|
|
SizedBox(width: 3.w),
|
|
getVIPBadge(
|
|
profile?.vipLevel ?? profile?.getVIP()?.name,
|
|
width: 45.w,
|
|
height: 25.w,
|
|
),
|
|
SizedBox(width: 3.w),
|
|
getWealthLevel(
|
|
profile?.wealthLevel ??
|
|
ref.userCardInfo?.userLevel?.wealthLevel ??
|
|
0,
|
|
width: 42.w,
|
|
height: 20.w,
|
|
fontSize: 9.sp,
|
|
),
|
|
SizedBox(width: 2.w),
|
|
getUserLevel(
|
|
profile?.charmLevel ??
|
|
ref.userCardInfo?.userLevel?.charmLevel ??
|
|
0,
|
|
width: 42.w,
|
|
height: 20.w,
|
|
fontSize: 9.sp,
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 2.w),
|
|
_buildSpecialIdMetaRow(context, profile),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildSpecialIdMetaRow(
|
|
BuildContext context,
|
|
SocialChatUserProfile? profile,
|
|
) {
|
|
final flagUrl = _countryFlagUrl(context, profile);
|
|
final hasSex = profile?.userSex != null;
|
|
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SCSpecialIdBadge(
|
|
idText: profile?.getID() ?? "",
|
|
showAnimated: profile?.hasSpecialId() ?? false,
|
|
assetPath: SCSpecialIdAssets.userId,
|
|
animationWidth: 62.w,
|
|
animationHeight: 24.w,
|
|
showTextBesideAnimated: true,
|
|
animatedTextSpacing: 0,
|
|
showAnimatedGradientText:
|
|
profile?.shouldShowColoredSpecialIdText() ?? false,
|
|
animationTextStyle: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
normalTextStyle: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
animationFit: BoxFit.contain,
|
|
),
|
|
if (flagUrl.isNotEmpty) ...[
|
|
SizedBox(width: 8.w),
|
|
_buildCountryFlag(flagUrl),
|
|
],
|
|
if (hasSex) ...[SizedBox(width: 7.w), _buildSexIcon(profile)],
|
|
],
|
|
);
|
|
}
|
|
|
|
String _countryFlagUrl(BuildContext context, SocialChatUserProfile? profile) {
|
|
final countryName = profile?.countryName ?? "";
|
|
try {
|
|
return Provider.of<SCAppGeneralManager>(
|
|
context,
|
|
listen: false,
|
|
).findCountryByName(countryName)?.nationalFlag ??
|
|
"";
|
|
} catch (_) {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
Widget _buildCountryFlag(String flagUrl) {
|
|
final trimmedUrl = flagUrl.trim();
|
|
if (trimmedUrl.isEmpty) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return ClipRRect(
|
|
borderRadius: BorderRadius.circular(2.w),
|
|
child: netImage(
|
|
url: trimmedUrl,
|
|
width: 22.w,
|
|
height: 15.w,
|
|
fit: BoxFit.cover,
|
|
noDefaultImg: true,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSexIcon(SocialChatUserProfile? profile) {
|
|
if (profile?.userSex == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
return xb(profile?.userSex, height: 15.w, color: null);
|
|
}
|
|
|
|
Widget _buildBadgeStrip(
|
|
String? userId,
|
|
SocialChatUserProfileManager ref,
|
|
SocialChatUserProfile? profile,
|
|
) {
|
|
return SCUserBadgeStrip(
|
|
userId: userId,
|
|
fallbackBadges: _roomCardFallbackBadges(ref, profile),
|
|
height: 70.w,
|
|
badgeHeight: 57.5.w,
|
|
longBadgeWidth: 145.w,
|
|
spacing: 20.w,
|
|
maxBadges: 12,
|
|
wrap: false,
|
|
reserveSpace: true,
|
|
);
|
|
}
|
|
|
|
List<WearBadge> _roomCardFallbackBadges(
|
|
SocialChatUserProfileManager ref,
|
|
SocialChatUserProfile? profile,
|
|
) {
|
|
final wearBadges =
|
|
profile?.wearBadge
|
|
?.where((item) => item.use != false && _hasBadgeUrl(item))
|
|
.toList() ??
|
|
const <WearBadge>[];
|
|
if (wearBadges.isNotEmpty) {
|
|
return wearBadges;
|
|
}
|
|
return ref.userCardInfo?.useBadge
|
|
?.map<WearBadge>(_roomUseBadgeToWearBadge)
|
|
.where(_hasBadgeUrl)
|
|
.toList() ??
|
|
const <WearBadge>[];
|
|
}
|
|
|
|
WearBadge _roomUseBadgeToWearBadge(room_card.UseBadge badge) {
|
|
return WearBadge(
|
|
animationUrl: badge.animationUrl,
|
|
badgeKey: badge.badgeKey,
|
|
badgeLevel: badge.badgeLevel,
|
|
badgeName: badge.badgeName,
|
|
expireTime: badge.expireTime?.toInt(),
|
|
id: badge.id,
|
|
milestone: badge.milestone,
|
|
notSelectUrl: badge.notSelectUrl,
|
|
selectUrl: badge.selectUrl,
|
|
type: badge.type,
|
|
userId: badge.userId,
|
|
use: true,
|
|
);
|
|
}
|
|
|
|
bool _hasBadgeUrl(WearBadge badge) {
|
|
return (badge.selectUrl ?? "").trim().isNotEmpty;
|
|
}
|
|
|
|
Widget _buildActions({
|
|
required BuildContext context,
|
|
required SocialChatUserProfileManager ref,
|
|
required RtcProvider rtcProvider,
|
|
required bool isSelf,
|
|
required bool canLeaveMic,
|
|
required num currentMicIndex,
|
|
}) {
|
|
if (isSelf) {
|
|
if (!canLeaveMic) {
|
|
return SizedBox(height: 55.w);
|
|
}
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
SizedBox(
|
|
width: 92.w,
|
|
child: _buildSheetAction(
|
|
iconAsset: _leaveMicActionIconAsset,
|
|
label: SCAppLocalizations.of(context)!.leavelTheMic,
|
|
onTap: () {
|
|
Navigator.of(context).pop();
|
|
rtcProvider.xiaMai(currentMicIndex);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
return Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildSheetAction(
|
|
iconAsset: "sc_images/room/sc_icon_send_user_message.png",
|
|
label: SCAppLocalizations.of(context)!.sayHi2,
|
|
onTap: () => _openChat(context),
|
|
),
|
|
),
|
|
Expanded(child: _buildFollowAction(context)),
|
|
Expanded(
|
|
child: _buildSheetAction(
|
|
iconAsset: "sc_images/room/sc_icon_at_tag_user.png",
|
|
label: SCAppLocalizations.of(context)!.atTag,
|
|
onTap: () => _openAtInput(context, ref),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: _buildSheetAction(
|
|
iconAsset: "sc_images/room/sc_icon_send_user_gift.png",
|
|
label: SCAppLocalizations.of(context)!.send,
|
|
onTap: () => _openGift(context, ref),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildSheetAction({
|
|
required String iconAsset,
|
|
required String label,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return SCDebounceWidget(
|
|
onTap: onTap,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
width: 42.w,
|
|
height: 42.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.58),
|
|
shape: BoxShape.circle,
|
|
border: Border.all(
|
|
color: const Color(0xff18F2B1).withValues(alpha: 0.18),
|
|
),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Image.asset(iconAsset, width: 28.w, height: 28.w),
|
|
),
|
|
SizedBox(height: 5.w),
|
|
SizedBox(
|
|
height: 31.w,
|
|
child: text(
|
|
label,
|
|
maxLines: 2,
|
|
textAlign: TextAlign.center,
|
|
textColor: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 12.sp,
|
|
lineHeight: 1.1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildFollowAction(BuildContext context) {
|
|
return SCDebounceWidget(
|
|
onTap: () {
|
|
final provider = Provider.of<SocialChatUserProfileManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
provider.followUser(widget.userId ?? "");
|
|
},
|
|
child: Selector<SocialChatUserProfileManager, bool>(
|
|
selector: (context, provider) => provider.userCardInfo?.follow ?? false,
|
|
shouldRebuild: (prev, next) => prev != next,
|
|
builder: (context, follow, _) {
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
width: 42.w,
|
|
height: 42.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.58),
|
|
shape: BoxShape.circle,
|
|
border: Border.all(
|
|
color: const Color(0xff18F2B1).withValues(alpha: 0.18),
|
|
),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Image.asset(
|
|
follow
|
|
? "sc_images/room/sc_icon_user_un_follow.png"
|
|
: "sc_images/room/sc_icon_user_follow.png",
|
|
width: 28.w,
|
|
height: 28.w,
|
|
),
|
|
),
|
|
SizedBox(height: 5.w),
|
|
SizedBox(
|
|
height: 31.w,
|
|
child: text(
|
|
follow
|
|
? SCAppLocalizations.of(context)!.followed
|
|
: SCAppLocalizations.of(context)!.follow,
|
|
maxLines: 2,
|
|
textAlign: TextAlign.center,
|
|
textColor: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 12.sp,
|
|
lineHeight: 1.1,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildHeaderIconButton({
|
|
required String iconAsset,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return SCDebounceWidget(
|
|
onTap: onTap,
|
|
child: Container(
|
|
width: 28.w,
|
|
height: 28.w,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withValues(alpha: 0.45),
|
|
shape: BoxShape.circle,
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Image.asset(
|
|
iconAsset,
|
|
width: 18.w,
|
|
height: 18.w,
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _openProfile(BuildContext context) {
|
|
final route =
|
|
"${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == widget.userId}&tageId=${widget.userId}";
|
|
Navigator.of(context).pop();
|
|
SCNavigatorUtils.push(navigatorKey.currentState?.context ?? context, route);
|
|
}
|
|
|
|
Future<void> _openChat(BuildContext context) async {
|
|
final rtmProvider = Provider.of<RtmProvider>(context, listen: false);
|
|
Navigator.of(context).pop();
|
|
var conversation = V2TimConversation(
|
|
type: ConversationType.V2TIM_C2C,
|
|
userID: widget.userId,
|
|
conversationID: '',
|
|
);
|
|
final didStart = await rtmProvider.startConversation(conversation);
|
|
if (!didStart || !mounted) return;
|
|
var json = jsonEncode(conversation.toJson());
|
|
SCNavigatorUtils.push(
|
|
navigatorKey.currentState!.context,
|
|
"${SCChatRouter.chat}?conversation=${Uri.encodeComponent(json)}",
|
|
);
|
|
}
|
|
|
|
Future<void> _openAtInput(
|
|
BuildContext context,
|
|
SocialChatUserProfileManager ref,
|
|
) async {
|
|
if (!SCRoomUtils.touristCanMsg(context)) {
|
|
return;
|
|
}
|
|
final nickname = ref.userCardInfo?.userProfile?.userNickname ?? "";
|
|
if (nickname.isEmpty) {
|
|
return;
|
|
}
|
|
Navigator.of(context).pop();
|
|
Navigator.push(
|
|
navigatorKey.currentState?.context ?? context,
|
|
PopRoute(
|
|
child: RoomMsgInput(
|
|
atTextContent: "<user id=\"${widget.userId}\">$nickname</user>",
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _openGift(BuildContext context, SocialChatUserProfileManager ref) {
|
|
Navigator.of(context).pop();
|
|
SmartDialog.show(
|
|
tag: "showGiftControl",
|
|
alignment: Alignment.bottomCenter,
|
|
maskColor: Colors.transparent,
|
|
animationType: SmartAnimationType.fade,
|
|
clickMaskDismiss: true,
|
|
builder: (_) {
|
|
return GiftPage(toUser: ref.userCardInfo?.userProfile);
|
|
},
|
|
);
|
|
}
|
|
|
|
String roleName(String role) {
|
|
if (role == SCRoomRolesType.HOMEOWNER.name) {
|
|
return SCAppLocalizations.of(context)!.owner;
|
|
} else if (role == SCRoomRolesType.ADMIN.name) {
|
|
return SCAppLocalizations.of(context)!.admin;
|
|
} else if (role == SCRoomRolesType.MEMBER.name) {
|
|
return SCAppLocalizations.of(context)!.member;
|
|
}
|
|
return SCAppLocalizations.of(context)!.guest;
|
|
}
|
|
|
|
_buildEmptyCpItem(bool canAdd) {
|
|
return Container(
|
|
width: ScreenUtil().screenWidth,
|
|
margin: EdgeInsets.symmetric(horizontal: 12.w),
|
|
height: 105.w,
|
|
decoration: BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage(
|
|
canAdd
|
|
? "sc_images/person/sc_icon_no_cp_item_bg.png"
|
|
: "sc_images/person/sc_icon_no_cp_item_bg4.png",
|
|
),
|
|
fit: BoxFit.fill,
|
|
),
|
|
),
|
|
child: Container(
|
|
margin: EdgeInsets.only(bottom: 13.w),
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
child: text(
|
|
SCAppLocalizations.of(context)!.noMatchedCP,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 12.sp,
|
|
textColor: canAdd ? Color(0xFFFF79A1) : Colors.white,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildCpItem(CPRes item) {
|
|
return Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
Container(
|
|
width: ScreenUtil().screenWidth,
|
|
margin: EdgeInsets.symmetric(horizontal: 15.w),
|
|
height: 135.w,
|
|
decoration: BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage("sc_images/person/sc_icon_no_cp_item_bg2.png"),
|
|
fit: BoxFit.fill,
|
|
),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(height: 68.w),
|
|
Container(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Image.asset(
|
|
"sc_images/person/sc_icon_cp_value_tag.png",
|
|
height: 18.w,
|
|
),
|
|
SizedBox(width: 5.w),
|
|
text(
|
|
_cpVaFormat(item.cpValue ?? 0),
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 12.sp,
|
|
textColor: Color(0xFFFF79A1),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
SizedBox(height: 8.w),
|
|
Container(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
child: text(
|
|
SCAppLocalizations.of(
|
|
context,
|
|
)!.timeSpentTogether(item.days ?? ""),
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 12.sp,
|
|
textColor: Color(0xFFFF79A1),
|
|
),
|
|
),
|
|
Container(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
child: text(
|
|
SCAppLocalizations.of(context)!.firstDay(item.firstDay ?? ""),
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 11.sp,
|
|
textColor: Colors.white,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
PositionedDirectional(
|
|
top: 30.w,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Column(
|
|
children: [
|
|
GestureDetector(
|
|
child: SizedBox(
|
|
height: 50.w,
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
netImage(
|
|
url: item.meUserAvatar ?? "",
|
|
width: 48.w,
|
|
shape: BoxShape.circle,
|
|
defaultImg:
|
|
"sc_images/general/sc_icon_avar_defalt.png",
|
|
),
|
|
Image.asset(
|
|
"sc_images/person/sc_icon_cp_head_ring.png",
|
|
),
|
|
],
|
|
),
|
|
),
|
|
onTap: () {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
replace: false,
|
|
"${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == item.meUserId}&tageId=${item.meUserId}",
|
|
);
|
|
},
|
|
),
|
|
|
|
Container(
|
|
alignment: Alignment.center,
|
|
width: 80.w,
|
|
height: 15.w,
|
|
child:
|
|
(item.meUserNickname?.length ?? 0) > 8
|
|
? Marquee(
|
|
text: item.meUserNickname ?? "",
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
decoration: TextDecoration.none,
|
|
),
|
|
scrollAxis: Axis.horizontal,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
blankSpace: 20.0,
|
|
velocity: 40.0,
|
|
pauseAfterRound: Duration(seconds: 1),
|
|
accelerationDuration: Duration(seconds: 1),
|
|
accelerationCurve: Curves.easeOut,
|
|
decelerationDuration: Duration(milliseconds: 550),
|
|
decelerationCurve: Curves.easeOut,
|
|
)
|
|
: Text(
|
|
item.meUserNickname ?? "",
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
decoration: TextDecoration.none,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(width: 120.w),
|
|
Column(
|
|
children: [
|
|
GestureDetector(
|
|
child: SizedBox(
|
|
height: 50.w,
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
netImage(
|
|
url: item.cpUserAvatar ?? "",
|
|
width: 48.w,
|
|
shape: BoxShape.circle,
|
|
defaultImg:
|
|
"sc_images/general/sc_icon_avar_defalt.png",
|
|
),
|
|
Image.asset(
|
|
"sc_images/person/sc_icon_cp_head_ring.png",
|
|
),
|
|
],
|
|
),
|
|
),
|
|
onTap: () {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
replace: false,
|
|
"${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == item.cpUserId}&tageId=${item.cpUserId}",
|
|
);
|
|
},
|
|
),
|
|
Container(
|
|
alignment: Alignment.center,
|
|
width: 80.w,
|
|
height: 15.w,
|
|
child:
|
|
(item.cpUserNickname?.length ?? 0) > 8
|
|
? Marquee(
|
|
text: item.cpUserNickname ?? "",
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
decoration: TextDecoration.none,
|
|
),
|
|
scrollAxis: Axis.horizontal,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
blankSpace: 20.0,
|
|
velocity: 40.0,
|
|
pauseAfterRound: Duration(seconds: 1),
|
|
accelerationDuration: Duration(seconds: 1),
|
|
accelerationCurve: Curves.easeOut,
|
|
decelerationDuration: Duration(milliseconds: 550),
|
|
decelerationCurve: Curves.easeOut,
|
|
)
|
|
: Text(
|
|
item.cpUserNickname ?? "",
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
fontSize: 10.sp,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
decoration: TextDecoration.none,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String getUserCardBg() {
|
|
return "";
|
|
}
|
|
|
|
String _cpVaFormat(double cpValue) {
|
|
int value = cpValue.toInt();
|
|
if (value > 99999) {
|
|
return "${(value / 1000).toStringAsFixed(0)}k";
|
|
}
|
|
return "$value";
|
|
}
|
|
}
|