944 lines
33 KiB
Dart
944 lines
33 KiB
Dart
import 'package:carousel_slider/carousel_slider.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:yumi/ui_kit/components/sc_debounce_widget.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
|
import '../../../../app_localizations.dart';
|
|
import '../../../../app/constants/sc_global_config.dart';
|
|
import '../../../../app/routes/sc_fluro_navigator.dart';
|
|
import '../../../../shared/business_logic/models/res/sc_index_banner_res.dart';
|
|
import '../../../../shared/tools/sc_banner_utils.dart';
|
|
import '../../../../shared/data_sources/sources/repositories/sc_room_repository_imp.dart';
|
|
import '../../../../shared/business_logic/models/res/follow_room_res.dart';
|
|
import '../../../../shared/business_logic/models/res/room_res.dart';
|
|
import '../../../../services/audio/rtc_manager.dart';
|
|
import '../../../../services/general/sc_app_general_manager.dart';
|
|
import '../../../../ui_kit/components/sc_compontent.dart';
|
|
import '../../../../ui_kit/components/text/sc_text.dart';
|
|
import '../../../../ui_kit/widgets/room/room_live_audio_indicator.dart';
|
|
import '../../../index/main_route.dart';
|
|
|
|
const Duration _kPartySkeletonAnimationDuration = Duration(milliseconds: 1450);
|
|
const Color _kPartySkeletonShell = Color(0xFF0F3730);
|
|
const Color _kPartySkeletonShellStrong = Color(0xFF1A4A41);
|
|
const Color _kPartySkeletonBoneBase = Color(0xFF2B5C53);
|
|
const Color _kPartySkeletonBoneHighlight = Color(0xFF5F8177);
|
|
const Color _kPartySkeletonBorder = Color(0x66D8B57B);
|
|
|
|
class SCHomePartyPage extends StatefulWidget {
|
|
const SCHomePartyPage({super.key});
|
|
|
|
@override
|
|
State<SCHomePartyPage> createState() => _HomePartyPageState();
|
|
}
|
|
|
|
class _HomePartyPageState extends State<SCHomePartyPage>
|
|
with SingleTickerProviderStateMixin {
|
|
List<FollowRoomRes> historyRooms = [];
|
|
String? lastId;
|
|
bool isLoading = false;
|
|
bool _isBannerLoading = false;
|
|
bool _isLeaderboardLoading = false;
|
|
final RefreshController _refreshController = RefreshController(
|
|
initialRefresh: false,
|
|
);
|
|
late final AnimationController _skeletonController;
|
|
List<SocialChatRoomRes> rooms = [];
|
|
int _currentIndex = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_skeletonController = AnimationController(
|
|
vsync: this,
|
|
duration: _kPartySkeletonAnimationDuration,
|
|
)..repeat();
|
|
loadData();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_skeletonController.dispose();
|
|
_refreshController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
resizeToAvoidBottomInset: false,
|
|
backgroundColor: Colors.transparent,
|
|
body: Stack(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
children: [
|
|
SmartRefresher(
|
|
enablePullDown: true,
|
|
enablePullUp: false,
|
|
controller: _refreshController,
|
|
onRefresh: () {
|
|
loadData();
|
|
},
|
|
onLoading: () {},
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Consumer<SCAppGeneralManager>(
|
|
builder: (context, ref, child) {
|
|
if (!_shouldShowBannerSection(ref)) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
return Padding(
|
|
padding: EdgeInsets.only(bottom: 12.w),
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
if (_shouldShowBannerSkeleton(ref))
|
|
_buildBannerSkeleton()
|
|
else
|
|
_banner(ref),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
Consumer<SCAppGeneralManager>(
|
|
builder: (context, ref, child) {
|
|
if (_shouldShowLeaderboardSkeleton(ref)) {
|
|
return _buildLeaderboardSkeleton();
|
|
}
|
|
return _banner2(ref);
|
|
},
|
|
),
|
|
_buildRoomsSection(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
_banner(SCAppGeneralManager ref) {
|
|
final banners = _partyBanners(ref);
|
|
final hasMultipleBanners = banners.length > 1;
|
|
if (banners.isEmpty) {
|
|
return Container();
|
|
}
|
|
return Stack(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
children: [
|
|
CarouselSlider(
|
|
options: CarouselOptions(
|
|
height: 95.w,
|
|
autoPlay: hasMultipleBanners,
|
|
// 启用自动播放
|
|
enlargeCenterPage: false,
|
|
// 居中放大当前页面
|
|
enableInfiniteScroll: hasMultipleBanners,
|
|
// 启用无限循环
|
|
autoPlayAnimationDuration: Duration(milliseconds: 800),
|
|
// 自动播放动画时长
|
|
viewportFraction: 1,
|
|
scrollPhysics:
|
|
hasMultipleBanners
|
|
? const BouncingScrollPhysics()
|
|
: const NeverScrollableScrollPhysics(),
|
|
// 视口分数
|
|
onPageChanged: (index, reason) {
|
|
_currentIndex = index;
|
|
setState(() {});
|
|
},
|
|
),
|
|
items:
|
|
banners.map((item) {
|
|
return GestureDetector(
|
|
child: netImage(
|
|
url: item.cover ?? "",
|
|
height: 95.w,
|
|
width: ScreenUtil().screenWidth * 0.9,
|
|
fit: BoxFit.fill,
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
),
|
|
onTap: () {
|
|
SCBannerUtils.openBanner(item, context);
|
|
},
|
|
);
|
|
}).toList(),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children:
|
|
banners.asMap().entries.map((entry) {
|
|
return Container(
|
|
width: 6.0,
|
|
height: 6.0,
|
|
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color:
|
|
_currentIndex == entry.key ? Colors.blue : Colors.white,
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
List<SCIndexBannerRes> _partyBanners(SCAppGeneralManager ref) {
|
|
if (ref.exploreBanners.isNotEmpty) {
|
|
return ref.exploreBanners;
|
|
}
|
|
return ref.homeBanners;
|
|
}
|
|
|
|
_banner2(SCAppGeneralManager ref) {
|
|
String roomGiftOneAvatar = "";
|
|
String roomGiftTwoAvatar = "";
|
|
String roomGiftThreeAvatar = "";
|
|
if (ref.appLeaderResult?.roomGiftsLeaderboard != null &&
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly != null) {
|
|
if ((ref.appLeaderResult?.roomGiftsLeaderboard?.weekly?.isNotEmpty ??
|
|
false) &&
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly?.first != null) {
|
|
roomGiftOneAvatar =
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly?.first.avatar ??
|
|
"";
|
|
}
|
|
|
|
if (ref.appLeaderResult!.roomGiftsLeaderboard!.weekly!.length > 1 &&
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly?[1] != null) {
|
|
roomGiftTwoAvatar =
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly![1].avatar ?? "";
|
|
}
|
|
if (ref.appLeaderResult!.roomGiftsLeaderboard!.weekly!.length > 2 &&
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly?[2] != null) {
|
|
roomGiftThreeAvatar =
|
|
ref.appLeaderResult?.roomGiftsLeaderboard?.weekly![2].avatar ?? "";
|
|
}
|
|
}
|
|
|
|
String wealthOneAvatar = "";
|
|
String wealthTwoAvatar = "";
|
|
String wealthThreeAvatar = "";
|
|
|
|
if (ref.appLeaderResult?.giftsSendLeaderboard != null &&
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly != null) {
|
|
if ((ref.appLeaderResult?.giftsSendLeaderboard?.weekly?.isNotEmpty ??
|
|
false) &&
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly?.first != null) {
|
|
wealthOneAvatar =
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly?.first.avatar ??
|
|
"";
|
|
}
|
|
|
|
if (ref.appLeaderResult!.giftsSendLeaderboard!.weekly!.length > 1 &&
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly?[1] != null) {
|
|
wealthTwoAvatar =
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly![1].avatar ?? "";
|
|
}
|
|
if (ref.appLeaderResult!.giftsSendLeaderboard!.weekly!.length > 2 &&
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly?[2] != null) {
|
|
wealthThreeAvatar =
|
|
ref.appLeaderResult?.giftsSendLeaderboard?.weekly![2].avatar ?? "";
|
|
}
|
|
}
|
|
|
|
String charmOneAvatar = "";
|
|
String charmTwoAvatar = "";
|
|
String charmThreeAvatar = "";
|
|
|
|
if (ref.appLeaderResult?.giftsReceivedLeaderboard != null &&
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly != null) {
|
|
if ((ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly?.isNotEmpty ??
|
|
false) &&
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly?.first !=
|
|
null) {
|
|
charmOneAvatar =
|
|
ref
|
|
.appLeaderResult
|
|
?.giftsReceivedLeaderboard
|
|
?.weekly
|
|
?.first
|
|
.avatar ??
|
|
"";
|
|
}
|
|
|
|
if (ref.appLeaderResult!.giftsReceivedLeaderboard!.weekly!.length > 1 &&
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly?[1] != null) {
|
|
charmTwoAvatar =
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly![1].avatar ??
|
|
"";
|
|
}
|
|
if (ref.appLeaderResult!.giftsReceivedLeaderboard!.weekly!.length > 2 &&
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly?[2] != null) {
|
|
charmThreeAvatar =
|
|
ref.appLeaderResult?.giftsReceivedLeaderboard?.weekly![2].avatar ??
|
|
"";
|
|
}
|
|
}
|
|
|
|
if (roomGiftOneAvatar.isEmpty &&
|
|
wealthOneAvatar.isEmpty &&
|
|
charmOneAvatar.isEmpty) {
|
|
return Container();
|
|
}
|
|
return SizedBox(
|
|
height: 130.w,
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 26.w,
|
|
top: 65.w,
|
|
child: head(url: wealthTwoAvatar, width: 30.w),
|
|
),
|
|
Positioned(
|
|
top: 35.w,
|
|
child: head(url: wealthOneAvatar, width: 36.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 24.w,
|
|
top: 65.w,
|
|
child: head(url: wealthThreeAvatar, width: 30.w),
|
|
),
|
|
Image.asset(
|
|
SCGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('wealth'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
"${SCMainRoute.webViewPage}?url=${Uri.encodeComponent(SCGlobalConfig.wealthRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 24.w,
|
|
top: 68.w,
|
|
child: head(url: roomGiftTwoAvatar, width: 30.w),
|
|
),
|
|
Positioned(
|
|
top: 35.w,
|
|
child: head(url: roomGiftOneAvatar, width: 38.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 25.w,
|
|
top: 69.w,
|
|
child: head(url: roomGiftThreeAvatar, width: 30.w),
|
|
),
|
|
Image.asset(
|
|
SCGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('room'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
"${SCMainRoute.webViewPage}?url=${Uri.encodeComponent(SCGlobalConfig.roomRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 26.w,
|
|
top: 66.w,
|
|
child: head(url: charmTwoAvatar, width: 30.w),
|
|
),
|
|
Positioned(
|
|
top: 38.w,
|
|
child: head(url: charmOneAvatar, width: 37.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 25.w,
|
|
top: 66.w,
|
|
child: head(url: charmThreeAvatar, width: 30.w),
|
|
),
|
|
Image.asset(
|
|
SCGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('charm'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
"${SCMainRoute.webViewPage}?url=${Uri.encodeComponent(SCGlobalConfig.charmRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildRoomsSection() {
|
|
if (isLoading && rooms.isEmpty) {
|
|
return _buildRoomGridSkeleton();
|
|
}
|
|
if (rooms.isEmpty) {
|
|
return GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () {
|
|
loadData();
|
|
},
|
|
child: mainEmpty(msg: SCAppLocalizations.of(context)!.noData),
|
|
);
|
|
}
|
|
return GridView.builder(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
childAspectRatio: 1,
|
|
mainAxisSpacing: 10,
|
|
crossAxisSpacing: 10,
|
|
),
|
|
padding: EdgeInsets.all(10),
|
|
itemCount: rooms.length,
|
|
itemBuilder: (context, index) {
|
|
return _buildItem(rooms[index], index);
|
|
},
|
|
);
|
|
}
|
|
|
|
bool _shouldShowLeaderboardSkeleton(SCAppGeneralManager ref) {
|
|
return _isLeaderboardLoading && !_hasLeaderboardData(ref);
|
|
}
|
|
|
|
bool _shouldShowBannerSection(SCAppGeneralManager ref) {
|
|
return _shouldShowBannerSkeleton(ref) || _partyBanners(ref).isNotEmpty;
|
|
}
|
|
|
|
bool _shouldShowBannerSkeleton(SCAppGeneralManager ref) {
|
|
return _isBannerLoading && _partyBanners(ref).isEmpty;
|
|
}
|
|
|
|
bool _hasLeaderboardData(SCAppGeneralManager ref) {
|
|
final appLeaderResult = ref.appLeaderResult;
|
|
return (appLeaderResult?.giftsSendLeaderboard?.weekly?.isNotEmpty ??
|
|
false) ||
|
|
(appLeaderResult?.roomGiftsLeaderboard?.weekly?.isNotEmpty ?? false) ||
|
|
(appLeaderResult?.giftsReceivedLeaderboard?.weekly?.isNotEmpty ??
|
|
false);
|
|
}
|
|
|
|
Widget _buildBannerSkeleton() {
|
|
return Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
|
child: SizedBox(
|
|
height: 95.w,
|
|
child: Stack(
|
|
alignment: Alignment.bottomCenter,
|
|
children: [
|
|
Positioned.fill(
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
border: Border.all(color: _kPartySkeletonBorder, width: 1.w),
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [_kPartySkeletonShellStrong, _kPartySkeletonShell],
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.14),
|
|
blurRadius: 18.w,
|
|
offset: Offset(0, 8.w),
|
|
),
|
|
],
|
|
),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
child: Stack(
|
|
children: [
|
|
Positioned.fill(
|
|
child: Opacity(
|
|
opacity: 0.45,
|
|
child: _buildSkeletonPanel(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: 10.w,
|
|
child: Row(
|
|
children: List.generate(3, (index) {
|
|
return Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 4.w),
|
|
child: _buildSkeletonBone(
|
|
width: 6.w,
|
|
height: 6.w,
|
|
shape: BoxShape.circle,
|
|
),
|
|
);
|
|
}),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildLeaderboardSkeleton() {
|
|
return SizedBox(
|
|
height: 130.w,
|
|
child: Row(
|
|
children: List.generate(3, (index) {
|
|
final bool isCenterCard = index == 1;
|
|
return Expanded(
|
|
child: Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
4.w,
|
|
isCenterCard ? 0 : 6.w,
|
|
4.w,
|
|
isCenterCard ? 0 : 6.w,
|
|
),
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(18.w),
|
|
border: Border.all(color: _kPartySkeletonBorder, width: 1.w),
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [_kPartySkeletonShellStrong, _kPartySkeletonShell],
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.18),
|
|
blurRadius: 14.w,
|
|
offset: Offset(0, 8.w),
|
|
),
|
|
],
|
|
),
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
Positioned.fill(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(1.w),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(17.w),
|
|
child: Opacity(
|
|
opacity: 0.34,
|
|
child: _buildSkeletonPanel(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
top: 21.w,
|
|
child: _buildSkeletonBone(
|
|
width: isCenterCard ? 42.w : 38.w,
|
|
height: isCenterCard ? 42.w : 38.w,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
PositionedDirectional(
|
|
start: 16.w,
|
|
top: 56.w,
|
|
child: _buildSkeletonBone(
|
|
width: 28.w,
|
|
height: 28.w,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
PositionedDirectional(
|
|
end: 16.w,
|
|
top: 56.w,
|
|
child: _buildSkeletonBone(
|
|
width: 28.w,
|
|
height: 28.w,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: 16.w,
|
|
child: _buildSkeletonBone(
|
|
width: isCenterCard ? 56.w : 48.w,
|
|
height: 10.w,
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildRoomGridSkeleton() {
|
|
return GridView.builder(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
childAspectRatio: 1,
|
|
mainAxisSpacing: 10,
|
|
crossAxisSpacing: 10,
|
|
),
|
|
padding: EdgeInsets.all(10.w),
|
|
itemCount: 6,
|
|
itemBuilder: (context, index) => _buildRoomSkeletonCard(),
|
|
);
|
|
}
|
|
|
|
Widget _buildRoomSkeletonCard() {
|
|
return Container(
|
|
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(14.w),
|
|
border: Border.all(color: _kPartySkeletonBorder, width: 1.w),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.16),
|
|
blurRadius: 16.w,
|
|
offset: Offset(0, 8.w),
|
|
),
|
|
],
|
|
),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(14.w),
|
|
child: Stack(
|
|
alignment: Alignment.bottomCenter,
|
|
children: [
|
|
Positioned.fill(
|
|
child: DecoratedBox(
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [_kPartySkeletonShellStrong, _kPartySkeletonShell],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Positioned.fill(
|
|
child: Padding(
|
|
padding: EdgeInsets.only(bottom: 34.w),
|
|
child: _buildSkeletonPanel(
|
|
borderRadius: BorderRadius.vertical(
|
|
top: Radius.circular(14.w),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
top: 12.w,
|
|
right: 12.w,
|
|
child: _buildSkeletonBone(
|
|
width: 30.w,
|
|
height: 12.w,
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
),
|
|
),
|
|
Positioned(
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
child: Container(
|
|
height: 34.w,
|
|
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
|
decoration: BoxDecoration(
|
|
color: Colors.black.withValues(alpha: 0.24),
|
|
border: Border(
|
|
top: BorderSide(
|
|
color: Colors.white.withValues(alpha: 0.05),
|
|
width: 1.w,
|
|
),
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
_buildSkeletonBone(
|
|
width: 20.w,
|
|
height: 13.w,
|
|
borderRadius: BorderRadius.circular(3.w),
|
|
),
|
|
SizedBox(width: 6.w),
|
|
Expanded(
|
|
child: _buildSkeletonBone(
|
|
height: 10.w,
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
),
|
|
),
|
|
SizedBox(width: 8.w),
|
|
_buildSkeletonBone(
|
|
width: 18.w,
|
|
height: 10.w,
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSkeletonPanel({
|
|
BorderRadius? borderRadius,
|
|
BoxShape shape = BoxShape.rectangle,
|
|
}) {
|
|
return AnimatedBuilder(
|
|
animation: _skeletonController,
|
|
builder: (context, child) {
|
|
final double slideOffset = (_skeletonController.value * 2) - 1;
|
|
return DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
shape: shape,
|
|
borderRadius:
|
|
shape == BoxShape.circle
|
|
? null
|
|
: (borderRadius ?? BorderRadius.circular(12.w)),
|
|
gradient: LinearGradient(
|
|
begin: Alignment(-1.4 + slideOffset, -0.2),
|
|
end: Alignment(1.4 + slideOffset, 0.2),
|
|
colors: const [
|
|
_kPartySkeletonBoneBase,
|
|
_kPartySkeletonBoneBase,
|
|
_kPartySkeletonBoneHighlight,
|
|
_kPartySkeletonBoneBase,
|
|
],
|
|
stops: const [0.0, 0.36, 0.54, 1.0],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildSkeletonBone({
|
|
double? width,
|
|
double? height,
|
|
BorderRadius? borderRadius,
|
|
BoxShape shape = BoxShape.rectangle,
|
|
}) {
|
|
return SizedBox(
|
|
width: width,
|
|
height: height,
|
|
child: _buildSkeletonPanel(borderRadius: borderRadius, shape: shape),
|
|
);
|
|
}
|
|
|
|
loadData() {
|
|
final generalManager = Provider.of<SCAppGeneralManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
setState(() {
|
|
isLoading = true;
|
|
_isBannerLoading =
|
|
generalManager.exploreBanners.isEmpty &&
|
|
generalManager.homeBanners.isEmpty;
|
|
_isLeaderboardLoading = generalManager.appLeaderResult == null;
|
|
});
|
|
SCChatRoomRepository()
|
|
.discovery(allRegion: true)
|
|
.then((values) {
|
|
rooms = values;
|
|
isLoading = false;
|
|
_refreshController.refreshCompleted();
|
|
_refreshController.loadComplete();
|
|
if (mounted) setState(() {});
|
|
})
|
|
.catchError((e) {
|
|
_refreshController.loadNoData();
|
|
_refreshController.refreshCompleted();
|
|
isLoading = false;
|
|
if (mounted) setState(() {});
|
|
});
|
|
generalManager.loadMainBanner().whenComplete(() {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_isBannerLoading = false;
|
|
});
|
|
});
|
|
generalManager.appLeaderboard().whenComplete(() {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_isLeaderboardLoading = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
_buildItem(SocialChatRoomRes res, int index) {
|
|
return SCDebounceWidget(
|
|
child: Container(
|
|
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
color: Colors.transparent,
|
|
),
|
|
child: Stack(
|
|
alignment: Alignment.bottomCenter,
|
|
children: [
|
|
Container(
|
|
padding: EdgeInsets.all(3.w),
|
|
decoration: BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage("sc_images/index/sc_icon_room_bord.png"),
|
|
fit: BoxFit.fill,
|
|
),
|
|
),
|
|
child: netImage(
|
|
url: resolveRoomCoverUrl(res.id, res.roomCover),
|
|
defaultImg: kRoomCoverDefaultImg,
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
width: 200.w,
|
|
height: 200.w,
|
|
),
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.symmetric(vertical: 6.w),
|
|
margin: EdgeInsets.symmetric(horizontal: 1.w),
|
|
decoration: BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage(
|
|
"sc_images/index/sc_icon_index_room_brd.png",
|
|
),
|
|
fit: BoxFit.fill,
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
SizedBox(width: 10.w),
|
|
Consumer<SCAppGeneralManager>(
|
|
builder: (_, provider, __) {
|
|
return netImage(
|
|
url:
|
|
"${provider.findCountryByName(res.countryName ?? "")?.nationalFlag}",
|
|
width: 20.w,
|
|
height: 13.w,
|
|
borderRadius: BorderRadius.circular(2.w),
|
|
);
|
|
},
|
|
),
|
|
SizedBox(width: 5.w),
|
|
Expanded(
|
|
child: SizedBox(
|
|
height: 17.w,
|
|
child: Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Transform.translate(
|
|
offset: Offset(0, -0.6.w),
|
|
child: text(
|
|
res.roomName ?? "",
|
|
fontSize: 13.sp,
|
|
textColor: Color(0xffffffff),
|
|
fontWeight: FontWeight.w400,
|
|
lineHeight: 1,
|
|
),
|
|
),
|
|
),
|
|
// (roomRes.roomProfile?.roomName?.length ?? 0) > 10
|
|
// ? Marquee(
|
|
// text: roomRes.roomProfile?.roomName ?? "",
|
|
// style: TextStyle(
|
|
// fontSize: 15.sp,
|
|
// color: Color(0xffffffff),
|
|
// fontWeight: FontWeight.w400,
|
|
// 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: 500,
|
|
// ),
|
|
// decelerationCurve: Curves.easeOut,
|
|
// )
|
|
// : Text(
|
|
// roomRes.roomProfile?.roomName ?? "",
|
|
// maxLines: 1,
|
|
// overflow: TextOverflow.ellipsis,
|
|
// style: TextStyle(
|
|
// fontSize: 15.sp,
|
|
// color: Color(0xffffffff),
|
|
// fontWeight: FontWeight.w400,
|
|
// decoration: TextDecoration.none,
|
|
// ),
|
|
// ),
|
|
),
|
|
),
|
|
SizedBox(width: 5.w),
|
|
(res.extValues?.roomSetting?.password?.isEmpty ?? false)
|
|
? SCRoomLiveAudioIndicator(width: 14.w, height: 14.w)
|
|
: Image.asset(
|
|
"sc_images/index/sc_icon_room_suo.png",
|
|
width: 20.w,
|
|
height: 20.w,
|
|
),
|
|
(res.extValues?.roomSetting?.password?.isEmpty ?? false)
|
|
? SizedBox(width: 3.w)
|
|
: Container(height: 10.w),
|
|
(res.extValues?.roomSetting?.password?.isEmpty ?? false)
|
|
? text(
|
|
res.extValues?.memberQuantity ?? "0",
|
|
fontSize: 10.sp,
|
|
lineHeight: 1,
|
|
)
|
|
: Container(height: 10.w),
|
|
SizedBox(width: 10.w),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
onTap: () {
|
|
Provider.of<RtcProvider>(
|
|
context,
|
|
listen: false,
|
|
).joinVoiceRoomSession(context, res.id ?? "");
|
|
},
|
|
);
|
|
}
|
|
}
|