1020 lines
36 KiB
Dart
1020 lines
36 KiB
Dart
import 'package:aslan/chatvibe_core/utilities/at_loading_manager.dart';
|
|
import 'package:carousel_slider/carousel_slider.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:aslan/chatvibe_ui/components/at_debounce_widget.dart';
|
|
import 'package:marquee/marquee.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
|
import '../../../../app_localizations.dart';
|
|
import '../../../../chatvibe_core/constants/at_global_config.dart';
|
|
import '../../../../chatvibe_core/routes/at_fluro_navigator.dart';
|
|
import '../../../../chatvibe_core/utilities/at_banner_utils.dart';
|
|
import '../../../../chatvibe_data/models/enum/at_vip_type.dart';
|
|
import '../../../../chatvibe_data/sources/repositories/room_repository_imp.dart';
|
|
import '../../../../chatvibe_domain/models/res/at_banner_leaderboard_res.dart';
|
|
import '../../../../chatvibe_domain/models/res/at_index_banner_res.dart';
|
|
import '../../../../chatvibe_domain/models/res/country_res.dart';
|
|
import '../../../../chatvibe_domain/models/res/follow_room_res.dart';
|
|
import '../../../../chatvibe_domain/models/res/room_res.dart';
|
|
import '../../../../chatvibe_managers/app_general_manager.dart';
|
|
import '../../../../chatvibe_managers/rtc_manager.dart';
|
|
import '../../../../chatvibe_ui/components/at_compontent.dart';
|
|
import '../../../../chatvibe_ui/components/text/at_text.dart';
|
|
import '../../../../chatvibe_ui/widgets/country/at_country_flag_image.dart';
|
|
import '../../../index/main_route.dart';
|
|
|
|
class HomePartyPage extends StatefulWidget {
|
|
@override
|
|
_HomePartyPageState createState() => _HomePartyPageState();
|
|
}
|
|
|
|
class _HomePartyPageState extends State<HomePartyPage>
|
|
with SingleTickerProviderStateMixin {
|
|
List<FollowRoomRes> historyRooms = [];
|
|
String? lastId;
|
|
bool isLoading = false;
|
|
final RefreshController _refreshController = RefreshController(
|
|
initialRefresh: false,
|
|
);
|
|
List<ChatVibeRoomRes> rooms = [];
|
|
int _currentIndex = 0;
|
|
final ScrollController _countryTabController = ScrollController();
|
|
final List<GlobalKey> _countryTabKeys = [];
|
|
List<Country> _countries = [];
|
|
Country? _selectedCountry;
|
|
int _dataRequestToken = 0;
|
|
bool _countryLoading = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
loadCountries();
|
|
loadData();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_countryTabController.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: [
|
|
Selector<AppGeneralManager, List<ATIndexBannerRes>>(
|
|
selector:
|
|
(_, provider) => List<ATIndexBannerRes>.unmodifiable(
|
|
provider.exploreBanners,
|
|
),
|
|
builder: (context, exploreBanners, child) {
|
|
return _banner(exploreBanners);
|
|
},
|
|
),
|
|
Selector<AppGeneralManager, ATBannerLeaderboardRes?>(
|
|
selector: (_, provider) => provider.appLeaderResult,
|
|
builder: (context, appLeaderResult, child) {
|
|
return _banner2(appLeaderResult);
|
|
},
|
|
),
|
|
_buildCountryTabs(),
|
|
rooms.isEmpty
|
|
? GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () {
|
|
loadData();
|
|
},
|
|
child:
|
|
isLoading
|
|
? Center(child: CupertinoActivityIndicator())
|
|
: mainEmpty(
|
|
msg: ATAppLocalizations.of(context)!.noData,
|
|
),
|
|
)
|
|
: Selector<AppGeneralManager, List<ATIndexBannerRes>>(
|
|
selector:
|
|
(_, provider) =>
|
|
List<ATIndexBannerRes>.unmodifiable(
|
|
provider.roomListBanners,
|
|
),
|
|
builder: (context, roomListBanners, child) {
|
|
return ListView.separated(
|
|
shrinkWrap: true,
|
|
padding: EdgeInsets.symmetric(vertical: 8.w),
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
itemCount: _partyRoomListItemCount(roomListBanners),
|
|
itemBuilder: (context, index) {
|
|
if (_isPartyBannerIndex(index, roomListBanners)) {
|
|
return _buildPartyBanner(roomListBanners);
|
|
}
|
|
final roomIndex = _roomIndexForListIndex(
|
|
index,
|
|
roomListBanners,
|
|
);
|
|
return _buildItem(rooms[roomIndex], roomIndex);
|
|
},
|
|
separatorBuilder: (
|
|
BuildContext context,
|
|
int index,
|
|
) {
|
|
return SizedBox(height: 4.w);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
bool _shouldShowPartyBanner(List<ATIndexBannerRes> roomListBanners) {
|
|
return rooms.length >= 3 && roomListBanners.isNotEmpty;
|
|
}
|
|
|
|
int _partyRoomListItemCount(List<ATIndexBannerRes> roomListBanners) {
|
|
return rooms.length + (_shouldShowPartyBanner(roomListBanners) ? 1 : 0);
|
|
}
|
|
|
|
bool _isPartyBannerIndex(int index, List<ATIndexBannerRes> roomListBanners) {
|
|
return _shouldShowPartyBanner(roomListBanners) && index == 3;
|
|
}
|
|
|
|
int _roomIndexForListIndex(
|
|
int index,
|
|
List<ATIndexBannerRes> roomListBanners,
|
|
) {
|
|
return _shouldShowPartyBanner(roomListBanners) && index > 3
|
|
? index - 1
|
|
: index;
|
|
}
|
|
|
|
Widget _buildPartyBanner(List<ATIndexBannerRes> roomListBanners) {
|
|
return SizedBox(
|
|
height: 97.w,
|
|
child: Container(
|
|
margin: EdgeInsetsDirectional.symmetric(horizontal: 17.w),
|
|
clipBehavior: Clip.antiAlias,
|
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12.w)),
|
|
child: CarouselSlider(
|
|
options: CarouselOptions(
|
|
height: 97.w,
|
|
autoPlay: false,
|
|
enlargeCenterPage: false,
|
|
enableInfiniteScroll: roomListBanners.length > 1,
|
|
viewportFraction: 1,
|
|
),
|
|
items:
|
|
roomListBanners.map((item) {
|
|
return _buildPartyBannerRemoteItem(item);
|
|
}).toList(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPartyBannerRemoteItem(ATIndexBannerRes item) {
|
|
return GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
child: netImage(
|
|
url: item.cover ?? "",
|
|
width: double.infinity,
|
|
height: 97.w,
|
|
fit: BoxFit.cover,
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
),
|
|
onTap: () {
|
|
ATBannerUtils.openBanner(item, context);
|
|
},
|
|
);
|
|
}
|
|
|
|
_banner(List<ATIndexBannerRes> exploreBanners) {
|
|
return Stack(
|
|
alignment: AlignmentDirectional.bottomCenter,
|
|
children: [
|
|
Container(
|
|
margin: EdgeInsets.symmetric(horizontal: 17.w),
|
|
child: CarouselSlider(
|
|
options: CarouselOptions(
|
|
height: 98.w,
|
|
autoPlay: true,
|
|
// 启用自动播放
|
|
enlargeCenterPage: false,
|
|
// 居中放大当前页面
|
|
enableInfiniteScroll: true,
|
|
// 启用无限循环
|
|
autoPlayAnimationDuration: Duration(milliseconds: 800),
|
|
// 自动播放动画时长
|
|
viewportFraction: 1,
|
|
// 视口分数
|
|
onPageChanged: (index, reason) {
|
|
_currentIndex = index;
|
|
setState(() {});
|
|
},
|
|
),
|
|
items:
|
|
exploreBanners.map((item) {
|
|
return GestureDetector(
|
|
child: netImage(
|
|
url: item.cover ?? "",
|
|
height: 98.w,
|
|
width: ScreenUtil().screenWidth * 0.9,
|
|
fit: BoxFit.contain,
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
),
|
|
onTap: () {
|
|
print('ads:${item.toJson()}');
|
|
ATBannerUtils.openBanner(item, context);
|
|
},
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children:
|
|
exploreBanners.asMap().entries.map((entry) {
|
|
return Container(
|
|
width: 6.0,
|
|
height: 6.0,
|
|
margin: EdgeInsets.symmetric(vertical: 15.0, horizontal: 4.0),
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color:
|
|
_currentIndex == entry.key ? Colors.blue : Colors.white,
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
_banner2(ATBannerLeaderboardRes? appLeaderResult) {
|
|
String avatarAt(List<LeaderboardUser>? users, int index) {
|
|
if (users == null || users.length <= index) return "";
|
|
return users[index].avatar ?? "";
|
|
}
|
|
|
|
final roomGiftWeekly = appLeaderResult?.roomGiftsLeaderboard?.weekly;
|
|
final wealthWeekly = appLeaderResult?.giftsSendLeaderboard?.weekly;
|
|
final charmWeekly = appLeaderResult?.giftsReceivedLeaderboard?.weekly;
|
|
|
|
final roomGiftOneAvatar = avatarAt(roomGiftWeekly, 0);
|
|
final roomGiftTwoAvatar = avatarAt(roomGiftWeekly, 1);
|
|
final roomGiftThreeAvatar = avatarAt(roomGiftWeekly, 2);
|
|
final wealthOneAvatar = avatarAt(wealthWeekly, 0);
|
|
final wealthTwoAvatar = avatarAt(wealthWeekly, 1);
|
|
final wealthThreeAvatar = avatarAt(wealthWeekly, 2);
|
|
final charmOneAvatar = avatarAt(charmWeekly, 0);
|
|
final charmTwoAvatar = avatarAt(charmWeekly, 1);
|
|
final charmThreeAvatar = avatarAt(charmWeekly, 2);
|
|
|
|
return SizedBox(
|
|
height: 120.w,
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 30.w,
|
|
top: 63.w,
|
|
child: head(url: wealthTwoAvatar, width: 28.w),
|
|
),
|
|
Positioned(
|
|
top: 35.w,
|
|
child: head(url: wealthOneAvatar, width: 36.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 30.w,
|
|
top: 63.w,
|
|
child: head(url: wealthThreeAvatar, width: 28.w),
|
|
),
|
|
Image.asset(
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('wealth'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
ATNavigatorUtils.push(
|
|
context,
|
|
"${MainRoute.webViewPage}?url=${Uri.encodeComponent(ATGlobalConfig.wealthRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 28.w,
|
|
top: 68.w,
|
|
child: head(url: roomGiftTwoAvatar, width: 28.w),
|
|
),
|
|
Positioned(
|
|
top: 35.w,
|
|
child: head(url: roomGiftOneAvatar, width: 38.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 29.w,
|
|
top: 68.w,
|
|
child: head(url: roomGiftThreeAvatar, width: 28.w),
|
|
),
|
|
Image.asset(
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('room'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
ATNavigatorUtils.push(
|
|
context,
|
|
"${MainRoute.webViewPage}?url=${Uri.encodeComponent(ATGlobalConfig.roomRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Expanded(
|
|
child: GestureDetector(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.center,
|
|
children: [
|
|
PositionedDirectional(
|
|
start: 28.w,
|
|
top: 66.w,
|
|
child: head(url: charmTwoAvatar, width: 28.w),
|
|
),
|
|
Positioned(
|
|
top: 38.w,
|
|
child: head(url: charmOneAvatar, width: 37.w),
|
|
),
|
|
PositionedDirectional(
|
|
end: 31.w,
|
|
top: 66.w,
|
|
child: head(url: charmThreeAvatar, width: 28.w),
|
|
),
|
|
Image.asset(
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getPopularLeaderboardBackgroundImage('charm'),
|
|
fit: BoxFit.fill,
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
ATNavigatorUtils.push(
|
|
context,
|
|
"${MainRoute.webViewPage}?url=${Uri.encodeComponent(ATGlobalConfig.charmRankUrl)}&showTitle=false",
|
|
replace: false,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildCountryTabs() {
|
|
_syncCountryTabKeys();
|
|
return Container(
|
|
height: 32.w,
|
|
margin: EdgeInsetsDirectional.only(start: 18.w, end: 18.w, top: 4.w),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
controller: _countryTabController,
|
|
scrollDirection: Axis.horizontal,
|
|
physics: const BouncingScrollPhysics(),
|
|
child: Row(
|
|
children: [
|
|
KeyedSubtree(key: _countryTabKeys[0], child: _buildHotTab()),
|
|
...List.generate(_countries.length, (index) {
|
|
final country = _countries[index];
|
|
return KeyedSubtree(
|
|
key: _countryTabKeys[index + 1],
|
|
child: _buildCountryTab(country, index + 1),
|
|
);
|
|
}),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 8.w),
|
|
ATDebounceWidget(
|
|
onTap: _showCountrySheet,
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
height: 23.w,
|
|
width: 23.w,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(color: const Color(0xff000000), width: 1.w),
|
|
),
|
|
child: Icon(
|
|
Icons.keyboard_arrow_down_rounded,
|
|
size: 18.w,
|
|
color: const Color(0xff333333),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildHotTab() {
|
|
final isSelected = _selectedCountry == null;
|
|
|
|
return Padding(
|
|
padding: EdgeInsetsDirectional.only(end: 6.w),
|
|
child: ATDebounceWidget(
|
|
onTap: () => _selectCountry(null, 0),
|
|
child: Container(
|
|
height: 32.w,
|
|
padding: EdgeInsetsDirectional.symmetric(horizontal: 13.w),
|
|
decoration: _countryTabDecoration(isSelected),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Image.asset(
|
|
"atu_images/index/at_icon_fire_department.png",
|
|
height: 19.w,
|
|
),
|
|
SizedBox(width: 3.w),
|
|
text(
|
|
ATAppLocalizations.of(context)!.hot,
|
|
textColor: const Color(0xff333333),
|
|
fontSize: 14.sp,
|
|
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
|
lineHeight: 1.1,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildCountryTab(Country country, int tabIndex) {
|
|
final isSelected = _isSameCountry(_selectedCountry, country);
|
|
|
|
return Padding(
|
|
padding: EdgeInsetsDirectional.only(end: 6.w),
|
|
child: ATDebounceWidget(
|
|
onTap: () => _selectCountry(country, tabIndex),
|
|
child: Container(
|
|
height: 32.w,
|
|
constraints: BoxConstraints(maxWidth: 144.w),
|
|
padding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
|
decoration: _countryTabDecoration(isSelected),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
_buildCountryFlag(country, width: 22.w, height: 16.w),
|
|
SizedBox(width: 6.w),
|
|
Flexible(
|
|
child: text(
|
|
_countryDisplayName(country),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
textColor:
|
|
isSelected
|
|
? const Color(0xff333333)
|
|
: const Color(0xff333333),
|
|
fontSize: 14.sp,
|
|
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
|
lineHeight: 1.1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
BoxDecoration _countryTabDecoration(bool isSelected) {
|
|
return BoxDecoration(
|
|
color: isSelected ? null : const Color(0xffeeeeee),
|
|
gradient:
|
|
isSelected
|
|
? const LinearGradient(
|
|
colors: [Color(0xffffd800), Color(0xffff9500)],
|
|
begin: AlignmentDirectional.topCenter,
|
|
end: AlignmentDirectional.bottomCenter,
|
|
)
|
|
: null,
|
|
borderRadius: BorderRadius.circular(40.w),
|
|
);
|
|
}
|
|
|
|
Widget _buildCountryFlag(
|
|
Country country, {
|
|
required double width,
|
|
required double height,
|
|
}) {
|
|
final flag = country.nationalFlag ?? "";
|
|
if (flag.isEmpty) {
|
|
return Container(
|
|
width: width,
|
|
height: height,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xffd9d9d9),
|
|
borderRadius: BorderRadius.circular(3.w),
|
|
),
|
|
);
|
|
}
|
|
|
|
return netImage(
|
|
url: flag,
|
|
width: width,
|
|
height: height,
|
|
fit: BoxFit.cover,
|
|
borderRadius: BorderRadius.circular(3.w),
|
|
noDefaultImg: true,
|
|
);
|
|
}
|
|
|
|
void _showCountrySheet() {
|
|
showModalBottomSheet(
|
|
context: context,
|
|
backgroundColor: Colors.transparent,
|
|
barrierColor: const Color(0x73000000),
|
|
isScrollControlled: true,
|
|
builder: (sheetContext) {
|
|
return SafeArea(
|
|
top: false,
|
|
child: Container(
|
|
constraints: BoxConstraints(
|
|
maxHeight: ScreenUtil().screenHeight * 0.6,
|
|
),
|
|
padding: EdgeInsetsDirectional.only(
|
|
start: 20.w,
|
|
end: 20.w,
|
|
top: 20.w,
|
|
bottom: MediaQuery.of(sheetContext).padding.bottom + 20.w,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadiusDirectional.vertical(
|
|
top: Radius.circular(20.w),
|
|
),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
text(
|
|
ATAppLocalizations.of(context)!.selectCountry,
|
|
textColor: const Color(0xff333333),
|
|
fontWeight: FontWeight.w700,
|
|
lineHeight: 1.1,
|
|
fontSize: 18.sp,
|
|
),
|
|
SizedBox(height: 20.w),
|
|
Flexible(
|
|
child:
|
|
_countries.isEmpty
|
|
? Center(
|
|
child:
|
|
_countryLoading
|
|
? const CupertinoActivityIndicator()
|
|
: mainEmpty(
|
|
msg:
|
|
ATAppLocalizations.of(
|
|
context,
|
|
)!.noData,
|
|
),
|
|
)
|
|
: GridView.builder(
|
|
shrinkWrap: true,
|
|
padding: EdgeInsets.zero,
|
|
physics: const BouncingScrollPhysics(),
|
|
gridDelegate:
|
|
SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 3,
|
|
mainAxisSpacing: 12.w,
|
|
crossAxisSpacing: 8.w,
|
|
childAspectRatio: 111 / 30,
|
|
),
|
|
itemCount: _countries.length,
|
|
itemBuilder: (context, index) {
|
|
final country = _countries[index];
|
|
return _buildCountrySheetItem(
|
|
country,
|
|
index + 1,
|
|
sheetContext,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildCountrySheetItem(
|
|
Country country,
|
|
int tabIndex,
|
|
BuildContext sheetContext,
|
|
) {
|
|
final isSelected = _isSameCountry(_selectedCountry, country);
|
|
|
|
return ATDebounceWidget(
|
|
onTap: () {
|
|
Navigator.of(sheetContext).pop();
|
|
_selectCountry(country, tabIndex);
|
|
},
|
|
child: Container(
|
|
height: 30.w,
|
|
padding: EdgeInsetsDirectional.symmetric(horizontal: 10.w),
|
|
decoration: BoxDecoration(
|
|
color: isSelected ? null : const Color(0xfff2f2f2),
|
|
gradient:
|
|
isSelected
|
|
? const LinearGradient(
|
|
colors: [Color(0xffffd800), Color(0xffff9500)],
|
|
begin: AlignmentDirectional.topCenter,
|
|
end: AlignmentDirectional.bottomCenter,
|
|
)
|
|
: null,
|
|
borderRadius: BorderRadius.circular(8.w),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
_buildCountryFlag(country, width: 18.w, height: 12.w),
|
|
SizedBox(width: 6.w),
|
|
Flexible(
|
|
child: Text(
|
|
_countryDisplayName(country),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: const Color(0xff333333),
|
|
fontSize: 13.sp,
|
|
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
|
decoration: TextDecoration.none,
|
|
height: 1.1,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _selectCountry(Country? country, int tabIndex) {
|
|
if (_isSameCountry(_selectedCountry, country)) {
|
|
_scrollCountryTabToIndex(tabIndex);
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
_selectedCountry = country;
|
|
rooms = [];
|
|
});
|
|
_scrollCountryTabToIndex(tabIndex);
|
|
loadData();
|
|
}
|
|
|
|
void _scrollCountryTabToIndex(int tabIndex) {
|
|
if (tabIndex < 0 || tabIndex >= _countryTabKeys.length) return;
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
final tabContext = _countryTabKeys[tabIndex].currentContext;
|
|
if (tabContext == null) return;
|
|
Scrollable.ensureVisible(
|
|
tabContext,
|
|
duration: const Duration(milliseconds: 250),
|
|
curve: Curves.easeOut,
|
|
alignment: 0.5,
|
|
);
|
|
});
|
|
}
|
|
|
|
void _syncCountryTabKeys() {
|
|
final total = _countries.length + 1;
|
|
while (_countryTabKeys.length < total) {
|
|
_countryTabKeys.add(GlobalKey());
|
|
}
|
|
if (_countryTabKeys.length > total) {
|
|
_countryTabKeys.removeRange(total, _countryTabKeys.length);
|
|
}
|
|
}
|
|
|
|
bool _isSameCountry(Country? left, Country? right) {
|
|
if (left == null || right == null) return left == right;
|
|
final leftKey = left.id ?? left.alphaTwo ?? left.countryName;
|
|
final rightKey = right.id ?? right.alphaTwo ?? right.countryName;
|
|
return leftKey == rightKey;
|
|
}
|
|
|
|
String _countryDisplayName(Country country) {
|
|
return country.countryName ?? "";
|
|
}
|
|
|
|
void loadCountries() {
|
|
_countryLoading = true;
|
|
ChatRoomRepository()
|
|
.roomLiveVoiceCountry()
|
|
.then((values) {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_countries = values;
|
|
_countryLoading = false;
|
|
});
|
|
})
|
|
.catchError((_) {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_countryLoading = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
loadData() {
|
|
final requestToken = ++_dataRequestToken;
|
|
final selectedCountry = _selectedCountry;
|
|
setState(() {
|
|
isLoading = true;
|
|
});
|
|
ATLoadingManager.exhibitOperation();
|
|
final Future<List<ChatVibeRoomRes>> request =
|
|
selectedCountry == null
|
|
? ChatRoomRepository().discovery()
|
|
: ChatRoomRepository().roomLiveVoiceExplore(
|
|
countryCode: selectedCountry.countryCode,
|
|
);
|
|
|
|
request
|
|
.then((values) {
|
|
if (!mounted || requestToken != _dataRequestToken) return;
|
|
rooms = values;
|
|
isLoading = false;
|
|
_refreshController.refreshCompleted();
|
|
_refreshController.loadComplete();
|
|
ATLoadingManager.veilRoutine();
|
|
if (mounted) setState(() {});
|
|
})
|
|
.catchError((e) {
|
|
if (!mounted || requestToken != _dataRequestToken) return;
|
|
_refreshController.loadNoData();
|
|
_refreshController.refreshCompleted();
|
|
ATLoadingManager.veilRoutine();
|
|
isLoading = false;
|
|
if (mounted) setState(() {});
|
|
});
|
|
Provider.of<AppGeneralManager>(context, listen: false).loadMainBanner();
|
|
Provider.of<AppGeneralManager>(context, listen: false).appLeaderboard();
|
|
}
|
|
|
|
String getRoomCoverHeaddress(ChatVibeRoomRes roomRes) {
|
|
var vip = roomRes.userProfile?.getVIP();
|
|
if (vip?.name == ATVIPType.DUKE.name) {
|
|
return "atu_images/vip/at_icon_vip4_room_cover_headdress.png";
|
|
} else if (vip?.name == ATVIPType.KING.name) {
|
|
return "atu_images/vip/at_icon_vip5_room_cover_headdress.png";
|
|
} else if (vip?.name == ATVIPType.EMPEROR.name) {
|
|
return "atu_images/vip/at_icon_vip6_room_cover_headdress.png";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
_buildItem(ChatVibeRoomRes res, int index) {
|
|
return ATDebounceWidget(
|
|
child: SizedBox(
|
|
height: 105.w,
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(13.w),
|
|
border:
|
|
index < 3
|
|
? null
|
|
: Border.all(
|
|
color:
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getExploreRoomBorderColor(),
|
|
width:
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getExploreRoomBorderWidth()
|
|
.w,
|
|
),
|
|
),
|
|
margin: EdgeInsetsDirectional.symmetric(
|
|
horizontal: 18.w,
|
|
vertical: 5.w,
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Stack(
|
|
children: [
|
|
netImage(
|
|
url: res.roomCover ?? "",
|
|
fit: BoxFit.cover,
|
|
borderRadius: BorderRadius.all(Radius.circular(12.w)),
|
|
width: 95.w,
|
|
height: 95.w,
|
|
),
|
|
PositionedDirectional(
|
|
top: 3.w,
|
|
end: 5.w,
|
|
child:
|
|
(res.extValues?.roomSetting?.password?.isNotEmpty ??
|
|
false)
|
|
? Image.asset(
|
|
"atu_images/index/at_icon_room_suo.png",
|
|
width: 16.w,
|
|
height: 16.w,
|
|
)
|
|
: Container(),
|
|
),
|
|
],
|
|
),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
SizedBox(height: 15.w),
|
|
Row(
|
|
children: [
|
|
SizedBox(width: 8.w),
|
|
ATCountryFlagImage(
|
|
countryName: res.countryName,
|
|
width: 25.w,
|
|
height: 15.w,
|
|
borderRadius: BorderRadius.all(
|
|
Radius.circular(3.w),
|
|
),
|
|
),
|
|
SizedBox(width: 5.w),
|
|
Container(
|
|
constraints: BoxConstraints(
|
|
maxHeight: 21.w,
|
|
maxWidth: 150.w,
|
|
),
|
|
child:
|
|
(res.roomName?.length ?? 0) >
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getExploreRoomNameMarqueeThreshold()
|
|
? Marquee(
|
|
text: res.roomName ?? "",
|
|
style: TextStyle(
|
|
fontSize: 15.sp,
|
|
color: Colors.black,
|
|
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(
|
|
res.roomName ?? "",
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
fontSize: 15.sp,
|
|
color: Colors.black,
|
|
decoration: TextDecoration.none,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 3.w),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
SizedBox(width: 8.w),
|
|
text(
|
|
"ID:${res.userProfile?.getID()}",
|
|
fontWeight: FontWeight.w600,
|
|
textColor: Colors.black,
|
|
fontSize: 15.sp,
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 3.w),
|
|
Container(
|
|
constraints: BoxConstraints(maxWidth: 180.w),
|
|
margin: EdgeInsetsDirectional.symmetric(
|
|
horizontal: 8.w,
|
|
),
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
spacing: 2.w,
|
|
children: List.generate(
|
|
(res.onlineUsers?.length ?? 0),
|
|
(index) {
|
|
return netImage(
|
|
url: res.onlineUsers?[index].userAvatar ?? "",
|
|
width: 23.w,
|
|
height: 23.w,
|
|
shape: BoxShape.circle,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
index < 3
|
|
? IgnorePointer(
|
|
child: Transform.translate(
|
|
offset: Offset(0, -3),
|
|
child: Image.asset(
|
|
ATGlobalConfig.businessLogicStrategy
|
|
.getExploreRankIconPattern(false, index + 1),
|
|
fit: BoxFit.fill,
|
|
),
|
|
),
|
|
)
|
|
: Container(),
|
|
PositionedDirectional(
|
|
end: 35.w,
|
|
bottom: 25.w,
|
|
child: Row(
|
|
children: [
|
|
Image.asset(
|
|
"atu_images/index/at_icon_room_flot_ani.gif",
|
|
width: 14.w,
|
|
height: 14.w,
|
|
),
|
|
text(
|
|
res.extValues?.memberQuantity ?? "0",
|
|
textColor: Colors.black38,
|
|
fontSize: 11.sp,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
onTap: () {
|
|
Provider.of<RtcProvider>(
|
|
context,
|
|
listen: false,
|
|
).joinRoom(context, res.id ?? "");
|
|
},
|
|
);
|
|
}
|
|
}
|