236 lines
6.4 KiB
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;
|
|
}
|
|
}
|
|
}
|