import 'package:comunic/helpers/calls_helper.dart'; import 'package:comunic/helpers/conversations_helper.dart'; import 'package:comunic/helpers/events_helper.dart'; import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/lists/call_members_list.dart'; import 'package:comunic/lists/users_list.dart'; import 'package:comunic/models/call_config.dart'; import 'package:comunic/models/call_member.dart'; import 'package:comunic/models/conversation.dart'; import 'package:comunic/ui/routes/main_route.dart'; import 'package:comunic/ui/widgets/comunic_back_button_widget.dart'; import 'package:comunic/ui/widgets/safe_state.dart'; import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; /// Call screen /// /// @author Pierre Hubert class CallScreen extends StatefulWidget { final int convID; const CallScreen({Key key, @required this.convID}) : assert(convID != null), assert(convID > 0), super(key: key); @override _CallScreenState createState() => _CallScreenState(); } class _CallScreenState extends SafeState { // Widget properties int get convID => widget.convID; // State properties Conversation _conversation; String _convName; CallConfig _conf; var _error = false; CallMembersList _membersList; UsersList _usersList; @override void initState() { super.initState(); _initCall(); } @override void dispose() { super.dispose(); _endCall(); } void _initCall() async { try { setState(() => _error = false); // First, load information about the conversation _conversation = await ConversationsHelper().getSingleOrThrow(convID); _convName = await ConversationsHelper.getConversationNameAsync(_conversation); assert(_convName != null); setState(() {}); // Join the call await CallsHelper.join(convID); // Get call configuration _conf = await CallsHelper.getConfig(); // Get current members of the call final membersList = await CallsHelper.getMembers(convID); membersList.removeUser(userID()); _usersList = await UsersHelper().getListWithThrow(membersList.usersID); _membersList = membersList; setState(() {}); // Register to events this.listenChangeState((e) { if (e.callID == convID) _membersList.add(CallMember(id: e.userID)); }); this.listen((e) { if (e.callID == convID) _removeMember(e.userID); }); this.listen((e) { if (e.callID == convID) _leaveCall(); }); } catch (e, stack) { print("Could not initialize call! $e\n$stack"); setState(() => _error = true); } } // Do clean up operations when call screen is destroyed void _endCall() async { try { // Leave the call await CallsHelper.leave(convID); } catch (e, stack) { print("Could not end call properly! $e\n$stack"); } } // Make us leave the call void _leaveCall() { MainController.of(context).popPage(); } void _removeMember(int memberID) { _membersList.removeUser(memberID); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: ComunicBackButton(), title: _convName == null ? CircularProgressIndicator() : Text(_convName), ), body: _buildBody(), ); } /// Build widget body Widget _buildBody() { // Handle errors if (_error) return buildErrorCard(tr("Could not initialize call!"), actions: [ MaterialButton( onPressed: () => _initCall(), child: Text(tr("Try again").toUpperCase()), ) ]); // Check if are not ready to show call UI if (_membersList == null) return buildCenteredProgressBar(); return Column( children: [_buildMembersArea()], ); } /// Build members area Widget _buildMembersArea() { return Center( child: Padding( padding: const EdgeInsets.all(8.0), child: RichText( text: TextSpan( children: _membersList .map((f) => TextSpan( text: _usersList.getUser(f.id).displayName + " ", style: TextStyle( color: f.status == MemberStatus.JOINED ? null : Colors.green))) .toList())), ), ); } }