import 'dart:async'; import 'dart:collection'; import 'dart:developer'; import 'package:hub/commons/actions/api_calls.dart'; import 'package:hub/app_state.dart'; import 'package:hub/commons/widgets/flutter_flow_theme.dart'; import 'package:hub/commons/widgets/flutter_flow_util.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; final dropdown = BehaviorSubject>.seeded( LinkedHashMap.from({ 'All': 'A', }), ); class MessageWellComponentWidget extends StatefulWidget { const MessageWellComponentWidget({super.key}); @override State createState() => _MessageWellComponentWidgetState(); } class _MessageWellComponentWidgetState extends State { StreamSubscription? _dropdownSubscription; @override void initState() { super.initState(); WidgetsBinding.instance?.addPostFrameCallback((_) { context.read().fetchMessages(); }); _dropdownSubscription = dropdown.stream.listen((_) { context.read().fetchMessages(); }); } @override void dispose() { _dropdownSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { final messages = context.read().getMessages(); return Align( alignment: Alignment.center, child: Padding( padding: const EdgeInsets.symmetric(vertical: 40.0), child: SizedBox( height: MediaQuery.of(context).size.height * 0.8, child: Column( children: [ _buildHandleMessageWell(context, FlutterFlowTheme.of(context)), _buildMenuMessageWell(context, FlutterFlowTheme.of(context)), Expanded( child: ListView.builder( itemCount: messages.length, shrinkWrap: true, physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { var message = messages[index]; return _buildMessageItem(context, message, index); }, ), ), ], ), ), ), ); } Widget _buildMenuMessageWell(BuildContext context, FlutterFlowTheme theme) { final dropdownItems = LinkedHashMap.from({ 'All': 'A', 'Personal': 'O', 'Global': 'C', }); return SizedBox( key: UniqueKey(), width: 200, height: 40, child: StreamBuilder( stream: dropdown.stream.map((event) => event.keys.first), builder: (context, snapshot) { final value = snapshot.data; return DropdownButtonFormField( value: value, decoration: InputDecoration( isDense: true, contentPadding: const EdgeInsets.symmetric(horizontal: 10.0), errorBorder: OutlineInputBorder( borderSide: BorderSide( color: theme.error, width: 2, ), borderRadius: BorderRadius.circular(10), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: theme.primary, width: 2, ), borderRadius: BorderRadius.circular(10), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: theme.primary, width: 2, ), borderRadius: BorderRadius.circular(10), ), disabledBorder: OutlineInputBorder( borderSide: BorderSide( color: theme.primary, width: 2, ), borderRadius: BorderRadius.circular(10), ), focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: theme.error, width: 2, ), borderRadius: BorderRadius.circular(10), ), border: OutlineInputBorder( borderSide: BorderSide( color: theme.primary, width: 2, ), borderRadius: BorderRadius.circular(10), ), filled: true, fillColor: theme.primary, ), onChanged: (String? newValue) { safeSetState(() => dropdown.value = LinkedHashMap.from({newValue!: dropdownItems[newValue].toString()})); }, items: dropdownItems.entries .map((entry) => DropdownMenuItem( value: entry.key, child: Text(entry.key), )) .toList(), style: theme.bodyMedium.copyWith( color: theme.primaryText, ), ); }, ), ); } Text _buildHandleMessageWell(BuildContext context, FlutterFlowTheme theme) { return Text( FFLocalizations.of(context).getVariableText( ptText: 'Mural de Mensagens', enText: 'Message Wall', ), style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', letterSpacing: 0.0, ), ); } Widget _buildMessageItem( BuildContext context, dynamic message, int index) { final theme = FlutterFlowTheme.of(context); String formatMessageOrigin(String messageOrigin) { final words = messageOrigin.split(' '); final formattedWords = words.map((word) { final firstLetter = word.substring(0, 1).toUpperCase(); final remainingLetters = word.substring(1).toLowerCase(); return '$firstLetter$remainingLetters'; }); return formattedWords.join(' '); } return GestureDetector( onTap: () => {}, child: Padding( padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), child: Container( width: MediaQuery.of(context).size.width * 0.9, height: 127.0, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), ), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: Container( width: 64.0, height: 64.0, decoration: const BoxDecoration(shape: BoxShape.circle), ), ), Expanded( child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 8.0), Center( child: Text( '~ ${formatMessageOrigin(message['MSG_ORIGEM_DESC'].toString())}', style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', color: theme.primary, fontSize: 14.0, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 8.0), Expanded( child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Text( formatMessageOrigin(message['MSG_TEXTO'].toString()), style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', color: theme.bodyMedium.color, fontSize: 14.0, ), softWrap: true, maxLines: 10, ), ), ), ], ), ) ], ), ), ), ); } } class MessageWellState { final List messages; int pageNumber; final bool allowScrollInSingleChildScrollView; MessageWellState({ required this.messages, this.pageNumber = 1, required this.allowScrollInSingleChildScrollView, }); MessageWellState copyWith({ List? messages, int? pageNumber, bool? allowScrollInSingleChildScrollView, }) { return MessageWellState( messages: messages ?? this.messages, pageNumber: pageNumber ?? this.pageNumber, allowScrollInSingleChildScrollView: allowScrollInSingleChildScrollView ?? this.allowScrollInSingleChildScrollView, ); } } class MessageWellNotifier extends StateNotifier { var _totalPageNumber = 1; int get totalPageNumber => _totalPageNumber; set totalPageNumber(int value) { _totalPageNumber = value; } MessageWellNotifier() : super(MessageWellState( messages: [], allowScrollInSingleChildScrollView: true, )) { fetchMessages(); } void fetchMessages() async { if (state.pageNumber <= totalPageNumber) { var apiCall = GetMessagesCall(); var response = await apiCall.call( devUUID: FFAppState().devUUID.toString(), userUUID: FFAppState().userUUID.toString(), cliID: FFAppState().cliUUID.toString(), atividade: 'getMensagens', pageSize: '100', pageNumber: state.pageNumber.toString(), tipoDestino: dropdown.value.values.first, ); if (response.statusCode == 200) { var messagesData = response.jsonBody['mensagens']; var newMessages = [...state.messages, ...messagesData]; state = state.copyWith(messages: newMessages); // var rExp = RegExp(r'\d+') // .allMatches(newMessages.toString()) // .map((e) => e.group(0)) // .toList(); // Provider.of(context, listen: false).setCounter(int.parse(response.jsonBody['total_pages'])); // totalPageNumber = int.parse(response.jsonBody['total_pages']); } else { log('Error fetching messages: ${response.statusCode}'); } } else { log('No more messages to fetch ...'); } } List getMessages() { return state.messages; } void incrementPageNumber() { if (state.pageNumber <= totalPageNumber) { state = state.copyWith(pageNumber: state.pageNumber + 1); } } } final messageWellProvider = StateNotifierProvider((ref) { return MessageWellNotifier(); });