yumi-flutter/lib/modules/home/popular/follow/sc_room_follow_page.dart

236 lines
6.4 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:yumi/app_localizations.dart';
import 'package:yumi/ui_kit/components/sc_page_list.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart';
import 'package:yumi/shared/business_logic/models/res/follow_room_res.dart';
import '../mine/sc_home_mine_room_card.dart';
import '../mine/sc_home_mine_skeleton.dart';
///加入的房间
class SCRoomFollowPage extends SCPageList {
const SCRoomFollowPage({super.key});
@override
SCPageListState createState() => _RoomFollowPageState();
}
class _RoomFollowPageState
extends SCPageListState<FollowRoomRes, SCRoomFollowPage>
with WidgetsBindingObserver, AutomaticKeepAliveClientMixin {
static const Duration _roomListRefreshInterval = Duration(seconds: 15);
Timer? _roomListRefreshTimer;
bool _isSilentRefreshingRooms = false;
bool _wasTickerModeEnabled = false;
bool _hasCompletedInitialLoad = false;
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
enablePullUp = false;
backgroundColor = Colors.transparent;
isGridView = true;
gridViewCount = 2;
gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 172 / 200,
mainAxisSpacing: 8.w,
crossAxisSpacing: 10.w,
);
padding = EdgeInsets.only(top: 8.w, bottom: 10.w);
loadData(1);
_startRoomListAutoRefresh();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_roomListRefreshTimer?.cancel();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_refreshRoomsSilently();
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final isTickerModeEnabled = TickerMode.valuesOf(context).enabled;
if (isTickerModeEnabled && !_wasTickerModeEnabled) {
_refreshRoomsSilently();
}
_wasTickerModeEnabled = isTickerModeEnabled;
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body:
!_hasCompletedInitialLoad && items.isEmpty && isLoading
? const SCHomeSkeletonShimmer(
builder: _buildFollowSkeletonContent,
)
: buildList(context),
);
}
static Widget _buildFollowSkeletonContent(
BuildContext context,
double progress,
) {
return buildHomeRoomGridSkeleton(progress);
}
@override
Widget buildItem(FollowRoomRes roomRes) {
return SCHomeMineRoomCard(room: roomRes);
}
@override
empty() {
return Align(
alignment: Alignment.topCenter,
child: Container(
width: double.infinity,
height: 76.w,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14.w),
border: Border.all(color: const Color(0x3306FFC0)),
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0x99111A1B), Color(0x992C4D42)],
),
),
child: Text(
SCAppLocalizations.of(context)!.youHaventJoinedAnyRoomsYet,
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
height: 20 / 14,
),
),
),
);
}
///加载数据
@override
loadPage({
required int page,
required Function(List<FollowRoomRes>) onSuccess,
Function? onErr,
}) async {
try {
final roomList = await SCAccountRepository().joined();
if (page == 1) {
_hasCompletedInitialLoad = true;
}
onSuccess(roomList);
} catch (e) {
if (page == 1) {
_hasCompletedInitialLoad = true;
}
if (onErr != null) {
onErr();
}
}
}
void _startRoomListAutoRefresh() {
_roomListRefreshTimer?.cancel();
_roomListRefreshTimer = Timer.periodic(_roomListRefreshInterval, (_) {
_refreshRoomsSilently();
});
}
bool _canRefreshRoomListSilently() {
return mounted &&
TickerMode.valuesOf(context).enabled &&
!_isSilentRefreshingRooms &&
!isLoading;
}
bool _sameRoom(FollowRoomRes previous, FollowRoomRes next) {
return previous.roomProfile?.id == next.roomProfile?.id &&
previous.roomProfile?.roomName == next.roomProfile?.roomName &&
previous.roomProfile?.roomCover == next.roomProfile?.roomCover &&
previous.roomProfile?.roomGameIcon == next.roomProfile?.roomGameIcon &&
previous.roomProfile?.displayMemberCount ==
next.roomProfile?.displayMemberCount &&
previous.roomProfile?.extValues?.existsPassword ==
next.roomProfile?.extValues?.existsPassword;
}
bool _sameRoomLists(List<FollowRoomRes> previous, List<FollowRoomRes> next) {
if (previous.length != next.length) {
return false;
}
for (int i = 0; i < previous.length; i++) {
if (!_sameRoom(previous[i], next[i])) {
return false;
}
}
return true;
}
bool _applyLatestRooms(List<FollowRoomRes> latestRooms) {
if (items.isEmpty || currentPage <= 1) {
if (_sameRoomLists(items, latestRooms)) {
return false;
}
items
..clear()
..addAll(latestRooms);
return true;
}
bool changed = false;
final replaceCount =
latestRooms.length < items.length ? latestRooms.length : items.length;
for (int i = 0; i < replaceCount; i++) {
if (!_sameRoom(items[i], latestRooms[i])) {
items[i] = latestRooms[i];
changed = true;
}
}
return changed;
}
Future<void> _refreshRoomsSilently() async {
if (!_canRefreshRoomListSilently()) {
return;
}
_isSilentRefreshingRooms = true;
try {
final latestRooms = await SCAccountRepository().joined();
if (!mounted || !TickerMode.valuesOf(context).enabled) {
return;
}
if (_applyLatestRooms(latestRooms)) {
setState(() {});
}
} catch (_) {
} finally {
_isSilentRefreshingRooms = false;
}
}
}