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 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) 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 previous, List 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 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 _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; } } }