import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/business_logic/models/res/login_res.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; import 'package:yumi/ui_kit/components/sc_compontent.dart'; import 'package:provider/provider.dart'; import 'package:yumi/shared/business_logic/models/res/join_room_res.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import 'package:yumi/app/constants/sc_screen.dart'; import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; // 默认位置 Offset kDefaultFloatOffset = Offset( ScreenUtil().screenWidth - width(90), ScreenUtil().screenHeight - height(120), ); class SCFloatIchart { /// 单例模式 static final SCFloatIchart _SCFloatIchart = SCFloatIchart._internal(); //1 factory SCFloatIchart() { return _SCFloatIchart; } SCFloatIchart._internal(); bool _inserted = false; OverlayEntry? overlayEntry; BuildContext? context; Offset offset = kDefaultFloatOffset; show() { if (overlayEntry != null) { remove(); // 先移除已有的 } var overlayState = Overlay.of(context!); overlayEntry = OverlayEntry( builder: (context) { if (SCNavigatorUtils.inLoginPage) { remove(); return Container(); } else { return buildToastLayout(); } }, ); overlayState.insert(overlayEntry!); _inserted = true; // 标记已插入 } bool isShow() { return _inserted; } remove() { if (overlayEntry != null && overlayEntry!.mounted) { if (_inserted) { overlayEntry?.remove(); _inserted = false; } } } LayoutBuilder buildToastLayout() { Timer? timer; return LayoutBuilder( builder: (context, constraints) { return Stack( children: [ Positioned( left: offset.dx, top: offset.dy, child: GestureDetector( //更新child的位置 onPanUpdate: (details) { var localPosition = details.delta; var dx = (offset.dx + localPosition.dx).clamp( 0.0, ScreenUtil().screenWidth - width(90), ); var dy = (offset.dy + localPosition.dy).clamp( 0.0, ScreenUtil().screenHeight - height(55) - kToolbarHeight, ); offset = Offset(dx, dy); overlayEntry!.markNeedsBuild(); }, //拖动结束,处理child贴边悬浮 onPanEnd: (details) { var oldPosition = offset.dx; var targets = offset.dx + width(80) > (ScreenUtil().screenWidth / 2) ? ScreenUtil().screenWidth - width(90) : 0; timer = Timer.periodic(Duration(milliseconds: 1), (t) { if (targets > 0) { oldPosition++; } else { oldPosition--; } offset = Offset(oldPosition.toDouble(), offset.dy); overlayEntry!.markNeedsBuild(); if (oldPosition < 0 || oldPosition > ScreenUtil().screenWidth - width(90)) { timer?.cancel(); } }); }, child: Container( child: float(), margin: EdgeInsets.only(bottom: height(kToolbarHeight)), ), ), ), ], ); }, ); } Widget float() { JoinRoomRes? room = Provider.of( context!, listen: false, ).currenRoom; // User user = Provider.of(context, listen: false).maiMap[0]; SocialChatLoginRes? user = AccountStorage().getCurrentUser(); return FloatRoomWindow(room: room, user: user, remove: remove); } void init(BuildContext context) { this.context = context; } } class FloatRoomWindow extends StatefulWidget { final JoinRoomRes? room; final SocialChatLoginRes? user; final Function remove; const FloatRoomWindow({Key? key, this.room, this.user, required this.remove}) : super(key: key); @override _FloatRoomWindowState createState() => _FloatRoomWindowState(); } class _FloatRoomWindowState extends State { @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return SCDebounceWidget( onTap: () { SCRoomUtils.openCurrentRoom(context); }, child: Container( height: 55.w, width: 90.w, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.w), color: SocialChatTheme.primaryLight, ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(width: 8.w), Stack( alignment: Alignment.center, children: [ netImage( url: widget.room?.roomProfile?.roomProfile?.roomCover ?? "", width: 40.w, height: 40.w, borderRadius: BorderRadius.circular(8.w), ), Image.asset( "sc_images/general/sc_icon_online_user.png", width: 15.w, height: 15.w, ), ], ), SizedBox(width: width(5)), SCDebounceWidget( onTap: () { Provider.of( context, listen: false, ).exitCurrentVoiceRoomSession(false); Timer(Duration(milliseconds: 550), () { widget.remove.call(); }); }, child: Padding( padding: EdgeInsets.all(5.w), child: Image.asset( "sc_images/index/sc_icon_room_flot_close.png", width: 20.w, height: 20.w, ), ), ), ], ), ), ); } }