Ver código fonte

fix:forum blank

Yulian 1 semana atrás
pai
commit
617e268148

+ 15 - 0
lib/src/layouts/components/template.dart

@@ -275,6 +275,21 @@ Widget loadingTemplate(VoidCallback setState){
   );
 }
 
+Widget loadingTemplateNoVoid(){
+  return Center(
+    child: Container(
+      height: 36,
+      child: LoadingIndicator(
+        indicatorType: Indicator.ballPulseRise,
+        colors: U.defaultRainbowColors(),
+        strokeWidth: 2,
+        backgroundColor: Colors.black.withValues(alpha: 0),
+        pathBackgroundColor: Colors.black,
+      ),
+    ),
+  );
+}
+
 Widget showButton(BuildContext context){
   var pid = U.getPidFromUrl(context.router.currentUrl);
   return Center(

+ 7 - 6
lib/src/layouts/functions/message.dart

@@ -48,8 +48,7 @@ class MessageFunction{
       CacheMan.writeData(url, tempData);
       Provider.of<MessageModule>(context, listen: false).setData(tempData);
       Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
-    }
-    else{
+    } else {
       Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
     }
   }
@@ -57,8 +56,9 @@ class MessageFunction{
   getDataForum(BuildContext context) async{
     String url = '/api/messages/search/myForum';
     var val = await CacheMan.readData(url);
+    final messageModule = Provider.of<MessageModule>(context,listen: false);
     if (val != null){
-      Provider.of<MessageModule>(context,listen: false).setForum(val['data']);
+      messageModule.setForum(val['data']);
     }
 
     var res = await apiAuthProvider.getData(url, null, context);
@@ -67,11 +67,12 @@ class MessageFunction{
       for (int i = 0; i < res.length; i++) {
         tempData.add(res[i]);
       }
+
       CacheMan.writeData(url, tempData);
-      Provider.of<MessageModule>(context, listen: false).setForum(tempData);
-      Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
+      messageModule.setForum(tempData);
+      messageModule.setFirstLoad(true);
     } else {
-      Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
+      messageModule.setFirstLoad(true);
     }
   }
 

+ 1 - 1
lib/src/layouts/mobile/history_forum.dart

@@ -321,7 +321,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
             child: Container(
               alignment: Alignment.topCenter,
               width: U.bodyWidth(context),
-              child: messageData.length == 0 && !isAfterLoad ? loadingTemplate((){}) : SingleChildScrollView(
+              child: messageData.length == 0 && !isAfterLoad ? loadingTemplateNoVoid() : SingleChildScrollView(
                 controller: scrollController,
                 reverse: isReverse,
                 padding: EdgeInsets.fromLTRB(10, 10, 10, 7),

+ 3 - 3
lib/src/layouts/mobile/menu_history.dart

@@ -151,7 +151,7 @@ class _MobHistoryPageState extends State<MobHistoryPage> with TickerProviderStat
                 ),
               ),
             ) : Provider.of<UserModule>(context).resetData() ? Container() : loadingTemplate(() {
-              if(mounted) if(mounted) setState(()=>_timeLimit=true);
+              if(mounted) setState(()=>_timeLimit=true);
             },),
           )
         ],
@@ -342,7 +342,7 @@ class _MobHistoryPageState extends State<MobHistoryPage> with TickerProviderStat
             }),
           ),
           !Provider.of<HistoryModule>(context).stopLoadHistory() || (Provider.of<HistoryModule>(context).isLoadHistory() && Provider.of<HistoryModule>(context).page() > 0)
-              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplate(() {},))
+              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
               : Provider.of<HistoryModule>(context).dataMisi().length == 0 && Provider.of<HistoryModule>(context).dataPending().length == 0
               ? NoDataPage()
               : Container(),
@@ -486,7 +486,7 @@ class _MobHistoryPageState extends State<MobHistoryPage> with TickerProviderStat
                 );
               })),
           !Provider.of<HistoryModule>(context).stopLoadHistory() || (Provider.of<HistoryModule>(context).isLoadHistory() && Provider.of<HistoryModule>(context).page() > 0)
-              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplate(() {},))
+              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
               : Provider.of<HistoryModule>(context).dataMisi().length == 0
               ? NoDataPage()
               : Container(),

+ 0 - 2
lib/src/layouts/mobile/menu_home.dart

@@ -61,9 +61,7 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
   }
 
   checkCompatibility() async{
-    print("checkCompatibility");
     var isCompatible = await U.isCompatibleWith(VersionKey.multiBahasa);
-    print("isCompatibleWith $isCompatible");
     if(isCompatible) {
       homeFunc.getContactCenter(context);
     }

+ 1 - 1
lib/src/layouts/mobile/message_broadcast.dart

@@ -275,7 +275,7 @@ class _MobMessageBroadcastPageState extends State<MobMessageBroadcastPage> {
             ),
           )
         ],
-      ):loadingTemplate(() {},),
+      ):loadingTemplateNoVoid(),
     );
   }
 }

+ 1 - 1
lib/src/layouts/mobile/message_chat.dart

@@ -261,7 +261,7 @@ class _MobMessageChatPageState extends State<MobMessageChatPage> {
               child: Container(width: bodyWidth,
                 child:LayoutBuilder(
                     builder: (context,constraint) {
-                      return messageData.length == 0 && !isAfterLoad ? loadingTemplate(() {},) : Column(
+                      return messageData.length == 0 && !isAfterLoad ? loadingTemplateNoVoid() : Column(
                         children: [
                           Expanded(
                             child: SingleChildScrollView(

+ 2 - 2
lib/src/layouts/mobile/message_list.dart

@@ -50,7 +50,7 @@ class _MobMessageListPageState extends State<MobMessageListPage> {
               child: EasyRefresh(
                 header: MaterialHeader(clamping: true, color: primaryColor),
                 onRefresh: () => messageFunc.onRefresh(context),
-                child: Provider.of<MessageModule>(context).data().isEmpty && !Provider.of<MessageModule>(context).firstLoad()? loadingTemplate(() {},) : Provider.of<MessageModule>(context).data().isEmpty ? Center(
+                child: Provider.of<MessageModule>(context).data().isEmpty && !Provider.of<MessageModule>(context).firstLoad()? loadingTemplateNoVoid() : Provider.of<MessageModule>(context).data().isEmpty ? Center(
                   child: Text('noMessageText').tr(),
                 ) : ListView(
                     padding: EdgeInsets.only(top: 12.0),
@@ -124,7 +124,7 @@ class _MobMessageListPageState extends State<MobMessageListPage> {
               child: EasyRefresh(
                 header: MaterialHeader(clamping: true, color: primaryColor),
                 onRefresh: () => messageFunc.onRefresh(context),
-                child: Provider.of<MessageModule>(context).forum().isEmpty && !Provider.of<MessageModule>(context).firstLoad()? loadingTemplate(() {},) : Provider.of<MessageModule>(context).forum().isEmpty ? Center(
+                child: Provider.of<MessageModule>(context).forum().isEmpty && !Provider.of<MessageModule>(context).firstLoad()? loadingTemplateNoVoid() : Provider.of<MessageModule>(context).forum().isEmpty ? Center(
                   child: Text('noMessageText').tr(),
                 ) : ListView(
                   padding: EdgeInsets.only(top: 16.0),

+ 1 - 1
lib/src/layouts/mobile/message_select.dart

@@ -62,7 +62,7 @@ class _MobMessageSelectPageState extends State<MobMessageSelectPage> {
     return Scaffold(
       backgroundColor: Colors.white,
       appBar: appBarTemplate(context: context, title: 'selectRecipient'.tr()),
-      body: !isLoaded ? loadingTemplate(() {},) : Column(
+      body: !isLoaded ? loadingTemplateNoVoid() : Column(
         children: [
           divider(),
           Expanded(

+ 1 - 1
lib/src/layouts/mobile/request_select.dart

@@ -84,7 +84,7 @@ class _MobReqSelectPageState extends State<MobReqSelectPage> {
             child: Container(
               alignment: Alignment.topCenter,
               width: U.bodyWidth(context),
-              child: Provider.of<RequestModule>(context).isLoad()? loadingTemplate(() {},) : SingleChildScrollView(
+              child: Provider.of<RequestModule>(context).isLoad()? loadingTemplateNoVoid() : SingleChildScrollView(
                 padding: EdgeInsets.symmetric(horizontal: 16),
                 child: Provider.of<RequestModule>(context).isEmpty() ? Center(child: Padding(
                     padding: const EdgeInsets.only(top: 24.0),

+ 1 - 1
lib/src/layouts/web/history_detail_pending.dart

@@ -112,7 +112,7 @@ class _WebHistoryDetailPendingPageState extends State<WebHistoryDetailPendingPag
                     ],
                   )
                 ],
-              ):loadingTemplate(() {},),
+              ):loadingTemplateNoVoid(),
             ),
           ),
           Container(

+ 1 - 1
lib/src/layouts/web/history_forum.dart

@@ -444,7 +444,7 @@ class _WebHistoryForumPageState extends State<WebHistoryForumPage> {
                     child: Column(
                       children: [
                         Expanded(
-                          child: messageData.length == 0 && !isAfterLoad ? loadingTemplate(() {},) : SingleChildScrollView(
+                          child: messageData.length == 0 && !isAfterLoad ? loadingTemplateNoVoid() : SingleChildScrollView(
                             controller: scrollController,
                             reverse: isReverse,
                             child: Column(

+ 2 - 2
lib/src/layouts/web/menu_history.dart

@@ -360,7 +360,7 @@ class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStat
             }),
           ),
           !Provider.of<HistoryModule>(context).stopLoadHistory() || (Provider.of<HistoryModule>(context).isLoadHistory() && Provider.of<HistoryModule>(context).page() > 0)
-              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplate(() {},))
+              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
               : Provider.of<HistoryModule>(context).dataMisi().isEmpty && Provider.of<HistoryModule>(context).dataPending().isEmpty
               ? NoDataPage()
               : Container(),
@@ -495,7 +495,7 @@ class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStat
               })
           ),
           !Provider.of<HistoryModule>(context).stopLoadHistory() || (Provider.of<HistoryModule>(context).isLoadHistory() && Provider.of<HistoryModule>(context).page() > 0)
-              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplate(() {},))
+              ? Container(margin: EdgeInsets.only(top: Provider.of<HistoryModule>(context).page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
               : Provider.of<HistoryModule>(context).dataMisi().length == 0 ? NoDataPage() : Container(),
         ],
       ),

+ 301 - 75
lib/src/layouts/web/message_list.dart

@@ -22,6 +22,7 @@ import 'dart:ui' as ui;
 import 'package:uuid/uuid.dart';
 
 import '../components/photo_chat.dart';
+import '../mobile/message_chat.dart';
 
 class WebMessageListPage extends StatefulWidget {
   Map<String, dynamic>? user;
@@ -69,15 +70,15 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
 
   @override
   void initState() {
-    Provider.of<MessageModule>(context, listen: false).reset();
+    messageModule = Provider.of<MessageModule>(context, listen: false);
+    messageModule.reset();
     if(widget.user == null){
       messageFunc.getUser(context);
     } else {
-      Provider.of<MessageModule>(context, listen: false).setUser(widget.user!);
+      messageModule.setUser(widget.user!);
       messageFunc.getDataMessages(context);
     }
-    username = Provider.of<MessageModule>(context, listen: false).user()['userId'];
-    messageModule = Provider.of<MessageModule>(context, listen: false);
+    username = messageModule.user()['userId'];
     // TODO: implement initState
     super.initState();
   }
@@ -126,6 +127,11 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
     forumData = [];
     page = 0;
     stopLoad = false;
+
+    // unsub dulu biar ga double2
+    subscription?.cancel();
+    subscription = null;
+
     getMessageForum();
     getCollectionDataForum();
   }
@@ -265,6 +271,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
     subscription = FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(forumChatId).snapshots().listen((querySnapshot) {
       querySnapshot.docChanges.forEach((result) async {
         var data = result.doc.data();
+        print(data);
         if(!mounted) return;
         if (result.type == DocumentChangeType.added && isAfterLoad) {
           if((username == data!['from']['user'] && forumData.where((element) => element['uniqueId'] == data['uniqueId']).isNotEmpty) || (username != data['from']['user'] && data['readStatus'] == 'DELETED')) {
@@ -306,21 +313,22 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
     });
   }
 
-  updateMessageDisplay(data){
-    var res = {};
-    var forum = messageModule.forum();
+  void updateMessageDisplay(Map<String, dynamic> data) {
+    final forum = messageModule.forum();
+    final res = <Map<String, dynamic>>[];
 
-    for(int i = 0; i < forum.length; i++){
-      var tmp = forum[i];
-      if(messageModule.forum()[i]['ticket']['ticketNo'] == activeForumId){
+    for (int i = 0; i < forum.length; i++) {
+      final tmp = Map<String, dynamic>.from(forum[i]);
+      if (tmp['ticket']['ticketNo'] == activeForumId) {
         tmp['msg'] = data['msg'];
       }
-      res.addAll(tmp);
+      res.add(tmp);
     }
 
     messageModule.setForum(res);
   }
 
+
   translateMessage(int t){
     var dt = t == 0 ? messageData : forumData;
     var loc = locale == 'zh' ? 'zh-cn' : locale;
@@ -429,31 +437,70 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
     }
 
     Widget chat(){
-      return Provider.of<MessageModule>(context).data().isEmpty ? Expanded(
-        child: Container(
-          child: Center(
-            child: Text('noMessageText'.tr()),
-          ),
+      final messageModule = Provider.of<MessageModule>(context);
+      final dataList = messageModule.data();
+      final currentUser = messageModule.user();
+      final forumList = messageModule.forum();
+
+      return dataList.isEmpty ? Expanded(
+        child: Center(
+          child: Text('noMessageText'.tr()),
         ),
       ) : SingleChildScrollView(
         padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
         child: Column(
           mainAxisSize: MainAxisSize.max,
-          children: List.generate(Provider.of<MessageModule>(context).data().length, (i) {
-            bool isMe0 = Provider.of<MessageModule>(context, listen: false).data()[i]['userId'] == Provider.of<MessageModule>(context, listen: false).user()['userId'] ? true : false;
+          children: List.generate(dataList.length, (i) {
+            final item = dataList[i];
+            final isMe = item['userId'] == currentUser['userId'];
+            final avatar = item['senderAvatar'];
+            final chatIdMatch = idChat != null && idChat == item['chatId'];
+            final recipientColor = U.getColor(isMe ? item['recipient'] : item['recipientId']);
+            final recipientName = item['recipientName'];
+            final senderName = item['senderName'];
+            final lastText = item['lastText'] ?? '';
+            final isImage = item['isImage'] ?? false;
+            final fileType = item['fileType'] ?? '';
+            final lastDate = item['lastDateTimeSend'];
+            final lastReadStatus = item['lastReadStatus'];
+            final forumReadStatus = forumList[i]['readStatus'];
+
             return GestureDetector(
-              onTap: () => selectMessage(Provider.of<MessageModule>(context, listen: false).data()[i], isMe0),
+              onTap: () => selectMessage(item, isMe),
               child: Container(
                 padding: EdgeInsets.all(10),
-                decoration: BoxDecoration(color: idChat != null && idChat == Provider.of<MessageModule>(context, listen: false).data()[i]['chatId'] ? Color(0xff26DA17).withValues(alpha: 0.2) : Colors.white, borderRadius: BorderRadius.all(Radius.circular(12))),
+                decoration: BoxDecoration(
+                  color: chatIdMatch ? Color(0xff26DA17).withAlpha(50) : Colors.white,
+                  borderRadius: BorderRadius.circular(12),
+                ),
                 child: Row(
                   children: [
-                    Provider.of<MessageModule>(context).data()[i]['senderAvatar'] != null && Provider.of<MessageModule>(context).data()[i]['senderAvatar'] != '' ? CircleAvatar(
-                      backgroundImage: NetworkImage(Provider.of<MessageModule>(context).data()[i]['senderAvatar']), radius: 24,
-                    ) : Container(
-                      height: 48, width: 48,
-                      decoration: BoxDecoration(shape: BoxShape.circle, color: Color(U.getColor(isMe0 ? Provider.of<MessageModule>(context).data()[i]['recipient'] : Provider.of<MessageModule>(context).data()[i]['recipientId']))),
-                      child: Center(child: Text(isMe0 ? Provider.of<MessageModule>(context).data()[i]['recipientName'] == "all_informants" ? "allInformants".tr()[0] : Provider.of<MessageModule>(context).data()[i]['recipientName'][0] : Provider.of<MessageModule>(context).data()[i]['senderName'][0], style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18))),
+                    avatar != null && avatar != ''
+                        ? CircleAvatar(
+                      backgroundImage: NetworkImage(avatar),
+                      radius: 24,
+                    )
+                        : Container(
+                      height: 48,
+                      width: 48,
+                      decoration: BoxDecoration(
+                        shape: BoxShape.circle,
+                        color: Color(recipientColor),
+                      ),
+                      child: Center(
+                        child: Text(
+                          isMe
+                              ? recipientName == "all_informants"
+                              ? "allInformants".tr()[0]
+                              : recipientName[0]
+                              : senderName[0],
+                          style: TextStyle(
+                            color: Colors.white,
+                            fontWeight: FontWeight.bold,
+                            fontSize: 18,
+                          ),
+                        ),
+                      ),
                     ),
                     SizedBox(width: 20),
                     Expanded(
@@ -461,54 +508,67 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                         crossAxisAlignment: CrossAxisAlignment.start,
                         children: [
                           Text(
-                            isMe0 ? Provider.of<MessageModule>(context).data()[i]['recipientName'] == "all_informants" ? "allInformants".tr() :
-                            Provider.of<MessageModule>(context).data()[i]['recipientName'] : Provider.of<MessageModule>(context).data()[i]['senderName'],
-                            style: TextStyle(
-                              fontWeight: FontWeight.w600,
-                            ),
+                            isMe
+                                ? recipientName == "all_informants"
+                                ? "allInformants".tr()
+                                : recipientName
+                                : senderName,
+                            style: TextStyle(fontWeight: FontWeight.w600),
                           ),
                           SizedBox(height: 5),
                           Row(
                             children: [
-                              isMe0 ? Padding(
-                                padding: EdgeInsets.only(right: 5),
-                                child: Icon(Icons.done_all, size: 18, color: Colors.blueGrey),
-                              ) : Container(),
-                              Provider.of<MessageModule>(context).data()[i]['isImage'] ? Align(
-                                alignment: Alignment.centerLeft,
-                                child: Row(
+                              if (isMe)
+                                Padding(
+                                  padding: EdgeInsets.only(right: 5),
+                                  child: Icon(Icons.done_all, size: 18, color: Colors.blueGrey),
+                                ),
+                              if (isImage)
+                                Row(
                                   children: [
-                                    Icon(Provider.of<MessageModule>(context).data()[i]['fileType'] == 'pdf' ? Icons.picture_as_pdf : Icons.image, color: Colors.black45, size: 16),
+                                    Icon(
+                                      fileType == 'pdf' ? Icons.picture_as_pdf : Icons.image,
+                                      color: Colors.black45,
+                                      size: 16,
+                                    ),
                                     SizedBox(width: 6),
-                                    Provider.of<MessageModule>(context).data()[i]['lastText'] == '' ? Provider.of<MessageModule>(context).data()[i]['fileType'] == 'pdf' ? Text('pdfFile'.tr()) : Text('photo'.tr()) : Container()
+                                    if (lastText == '')
+                                      Text(fileType == 'pdf' ? 'pdfFile'.tr() : 'photo'.tr()),
                                   ],
                                 ),
-                              ) : Container(),
                               Expanded(
-                                child: Text(Provider.of<MessageModule>(context).data()[i]['lastText'], style: TextStyle(fontSize: 13), maxLines: 1, overflow: TextOverflow.ellipsis),
-                              )
+                                child: Text(
+                                  lastText,
+                                  style: TextStyle(fontSize: 13),
+                                  maxLines: 1,
+                                  overflow: TextOverflow.ellipsis,
+                                ),
+                              ),
                             ],
-                          )
+                          ),
                         ],
                       ),
                     ),
                     SizedBox(width: 20),
                     Column(
-                      // mainAxisAlignment: MainAxisAlignment.center,
                       crossAxisAlignment: CrossAxisAlignment.end,
                       children: [
                         Text(
-                          convertDate(Provider.of<MessageModule>(context).data()[i]['lastDateTimeSend'], context.locale.toString()),
+                          convertDate(lastDate, context.locale.toString()),
                           style: TextStyle(
                             fontSize: 11,
-                            fontWeight: Provider.of<MessageModule>(context).forum()[i]['readStatus']=='UNREAD' ? FontWeight.w600 : FontWeight.w300,
-                            color: Provider.of<MessageModule>(context).data()[i]['lastReadStatus'] == 'UNREAD' && !isMe0 ? primaryColor : Colors.black45,
+                            fontWeight: forumReadStatus == 'UNREAD' ? FontWeight.w600 : FontWeight.w300,
+                            color: lastReadStatus == 'UNREAD' && !isMe ? primaryColor : Colors.black45,
                           ),
                         ),
                         SizedBox(height: 12),
-                        Icon(size: 12, Icons.circle, color: primaryColor.withValues(alpha: Provider.of<MessageModule>(context).data()[i]['lastReadStatus'] == 'UNREAD' && !isMe0 ? 1 : 0))
+                        Icon(
+                          Icons.circle,
+                          size: 12,
+                          color: primaryColor.withAlpha(lastReadStatus == 'UNREAD' && !isMe ? 1 : 0),
+                        ),
                       ],
-                    )
+                    ),
                   ],
                 ),
               ),
@@ -518,20 +578,181 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
       );
     }
 
+    Widget webChat(BuildContext context) {
+      final messageModule = Provider.of<MessageModule>(context);
+      final dataList = messageModule.data();
+      final currentUser = messageModule.user();
+      final isFirstLoad = messageModule.firstLoad();
+
+      return Container(
+        padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
+        alignment: Alignment.topCenter,
+        child: dataList.isEmpty && !isFirstLoad
+            ? loadingTemplateNoVoid()
+            : dataList.isEmpty
+            ? Center(child: Text('noMessageText'.tr()))
+            : ListView.builder(
+          itemCount: dataList.length,
+          itemBuilder: (context, i) {
+            final item = dataList[i];
+            final isMe = item['userId'] == currentUser['userId'];
+            final avatar = item['senderAvatar'];
+            final recipientName = item['recipientName'];
+            final senderName = item['senderName'];
+            final lastText = item['lastText'] ?? '';
+            final isImage = item['isImage'] ?? false;
+            final fileType = item['fileType'] ?? '';
+            final lastDate = item['lastDateTimeSend'];
+            final lastReadStatus = item['lastReadStatus'];
+            final chatId = item['chatId'];
+            final recipientId = item['recipientId'];
+            final recipient = item['recipient'];
+            final id = item['id'];
+
+            return GestureDetector(
+              onTap: () {
+                selectMessage(item, isMe);
+                // navigateTo(
+                //   context,
+                //   MobMessageChatPage(
+                //     currentUser,
+                //     chatId,
+                //     isMe ? recipientName : senderName,
+                //     id.toString(),
+                //     isMe,
+                //     recipient,
+                //   ),
+                // );
+                messageFunc.onRefresh(context);
+              },
+              child: Container(
+                padding: EdgeInsets.all(10),
+                margin: EdgeInsets.only(bottom: 12),
+                decoration: BoxDecoration(
+                  color: idChat != null && idChat == chatId
+                      ? Color(0xff26DA17).withAlpha(50)
+                      : Colors.white,
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Row(
+                  children: [
+                    avatar != null && avatar != ''
+                        ? CircleAvatar(
+                      backgroundImage: NetworkImage(avatar),
+                      radius: 24,
+                    )
+                        : Container(
+                      height: 48,
+                      width: 48,
+                      decoration: BoxDecoration(
+                        shape: BoxShape.circle,
+                        color: Color(U.getColor(isMe ? recipient : recipientId)),
+                      ),
+                      child: Center(
+                        child: Text(
+                          isMe
+                              ? recipientName == "all_informants"
+                              ? "allInformants".tr()[0]
+                              : recipientName[0]
+                              : senderName[0],
+                          style: TextStyle(
+                            color: Colors.white,
+                            fontWeight: FontWeight.bold,
+                            fontSize: 18,
+                          ),
+                        ),
+                      ),
+                    ),
+                    SizedBox(width: 20),
+                    Expanded(
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          Text(
+                            isMe
+                                ? recipientName == "all_informants"
+                                ? "allInformants".tr()
+                                : recipientName
+                                : senderName,
+                            style: TextStyle(fontWeight: FontWeight.w600),
+                          ),
+                          SizedBox(height: 5),
+                          Row(
+                            children: [
+                              if (isMe)
+                                Padding(
+                                  padding: EdgeInsets.only(right: 4),
+                                  child: Icon(Icons.done_all, size: 18, color: Colors.blueGrey),
+                                ),
+                              if (isImage)
+                                Row(
+                                  children: [
+                                    Icon(
+                                      fileType == 'pdf' ? Icons.picture_as_pdf : Icons.image,
+                                      color: Colors.black45,
+                                      size: 16,
+                                    ),
+                                    SizedBox(width: 6),
+                                    if (lastText == '')
+                                      Text(fileType == 'pdf' ? 'pdfFile'.tr() : 'photo'.tr()),
+                                  ],
+                                ),
+                              Expanded(
+                                child: Text(
+                                  lastText,
+                                  style: TextStyle(fontSize: 13),
+                                  maxLines: 1,
+                                  overflow: TextOverflow.ellipsis,
+                                ),
+                              ),
+                            ],
+                          ),
+                        ],
+                      ),
+                    ),
+                    SizedBox(width: 20),
+                    Column(
+                      crossAxisAlignment: CrossAxisAlignment.end,
+                      children: [
+                        Text(
+                          messageFunc.timeSet(lastDate),
+                          style: TextStyle(
+                            fontSize: 11,
+                            color: lastReadStatus == 'UNREAD' && !isMe ? Colors.green : Colors.black45,
+                          ),
+                        ),
+                        SizedBox(height: 4),
+                        Icon(
+                          Icons.circle,
+                          color: Colors.green.withAlpha(lastReadStatus == 'UNREAD' && !isMe ? 1 : 0),
+                        ),
+                      ],
+                    ),
+                  ],
+                ),
+              ),
+            );
+          },
+        ),
+      );
+    }
+
+    // tampilan list pesan forum di sebelah kiri
     Widget forum(){
-      return Provider.of<MessageModule>(context).forum().isEmpty ? Center(
+      final messageModule = Provider.of<MessageModule>(context);
+      return messageModule.forum().isEmpty ? Center(
         child: Text('noMessageText'.tr()),
       ) : SingleChildScrollView(
         padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
         child: Column(
           mainAxisSize: MainAxisSize.max,
-          children: List.generate(Provider.of<MessageModule>(context).forum().length, (i){
-            bool isMe0 = Provider.of<MessageModule>(context, listen: false).forum()[i]['userId'] == Provider.of<MessageModule>(context, listen: false).user()['userId'] ? true : false;
+          children: List.generate(messageModule.forum().length, (i){
+            bool isMe0 = messageModule.forum()[i]['userId'] == messageModule.user()['userId'] ? true : false;
             return GestureDetector(
               onTap: (){
-                var dt = Provider.of<MessageModule>(context, listen: false).forum()[i]['ticket'];
+                var dt = messageModule.forum()[i]['ticket'];
                 messageFunc.setAsRead(context, dt['ticketNo']);
-                Provider.of<MessageModule>(context, listen: false).forum()[i]['readStatus'] = 'READ';
+                messageModule.forum()[i]['readStatus'] = 'READ';
                 selectMessageForum(dt);
                 setState(() {
                   isAfterLoad = false;
@@ -540,7 +761,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
               },
               child: Container(
                   decoration: BoxDecoration(
-                    color: activeForumId != '' && Provider.of<MessageModule>(context, listen: false).forum()[i]['ticket']['ticketNo'] == activeForumId ? Color(0xff26DA17).withValues(alpha: 0.2) : Colors.white,
+                    color: activeForumId != '' && messageModule.forum()[i]['ticket']['ticketNo'] == activeForumId ? Color(0xff26DA17).withValues(alpha: 0.2) : Colors.white,
                     borderRadius: BorderRadius.all(Radius.circular(12)),
                   ),
                   width: double.infinity,
@@ -554,7 +775,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                               height: 48,
                               width: 48,
                               decoration: BoxDecoration(
-                                image: DecorationImage(image: NetworkImage(Provider.of<MessageModule>(context).forum()[i]['ticket']['_requestImage'])),
+                                image: DecorationImage(image: NetworkImage(messageModule.forum()[i]['ticket']['_requestImage'])),
                                 // color: Colors.green,
                                 border: Border.all(color: Colors.black12),
                                 borderRadius: BorderRadius.circular(50),
@@ -571,7 +792,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                                     children: [
                                       Flexible(
                                         child: Text(
-                                          Provider.of<MessageModule>(context).forum()[i]['ticket'][U.langColumn(context, 'requestSubject')],
+                                          messageModule.forum()[i]['ticket'][U.langColumn(context, 'requestSubject')],
                                           maxLines: 1,
                                           overflow: TextOverflow.ellipsis,
                                           softWrap: false,
@@ -582,11 +803,11 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                                       ),
                                       SizedBox(width: 4),
                                       Text(
-                                        convertDate(Provider.of<MessageModule>(context).forum()[i]['datetime'], context.locale.toString()),
+                                        convertDate(messageModule.forum()[i]['datetime'], context.locale.toString()),
                                         style: TextStyle(
                                           fontSize: 11,
-                                          fontWeight: Provider.of<MessageModule>(context).forum()[i]['readStatus']=='UNREAD' ? FontWeight.w600 : FontWeight.w300,
-                                          color: Provider.of<MessageModule>(context).forum()[i]['readStatus']=='UNREAD' && !isMe0 ? primaryColor : Colors.black45,
+                                          fontWeight: messageModule.forum()[i]['readStatus']=='UNREAD' ? FontWeight.w600 : FontWeight.w300,
+                                          color: messageModule.forum()[i]['readStatus']=='UNREAD' && !isMe0 ? primaryColor : Colors.black45,
                                         ),
                                       ),
                                     ],
@@ -598,7 +819,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                                     children: [
                                       Flexible(
                                         child: Text(
-                                          Provider.of<MessageModule>(context).forum()[i]['msg'],
+                                          messageModule.forum()[i]['msg'],
                                           overflow: TextOverflow.ellipsis,
                                           maxLines: 2,
                                         ),
@@ -607,7 +828,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                                       Icon(
                                         Icons.circle,
                                         size: 12,
-                                        color: Provider.of<MessageModule>(context).forum()[i]['readStatus']=='UNREAD' && !isMe0 ? primaryColor : Colors.transparent,
+                                        color: messageModule.forum()[i]['readStatus']=='UNREAD' && !isMe0 ? primaryColor : Colors.transparent,
                                       ),
                                     ],
                                   ),
@@ -635,7 +856,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
           ),
           divider(),
           Expanded(
-            child: messageData.isEmpty && !isAfterLoad ? loadingTemplate(() {},) : SingleChildScrollView(
+            child: messageData.isEmpty && !isAfterLoad ? loadingTemplateNoVoid() : SingleChildScrollView(
               padding: const EdgeInsets.fromLTRB(10, 10, 10, 7),
               controller: scrollController,
               reverse: isReverse,
@@ -787,6 +1008,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
       setState(() {});
     }
 
+    // tampilan list chat forum yg sebelah kanan
     Widget forumList(){
       return activeForumId == '' ? Center(child: Text("noMessageText".tr())) : Column(
         children: [
@@ -796,7 +1018,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
           ),
           divider(),
           Expanded(
-            child: forumData.isEmpty && !isAfterLoad ? loadingTemplate(() {},) : Align(
+            child: forumData.isEmpty && !isAfterLoad ? loadingTemplateNoVoid() : Align(
               alignment: Alignment.topCenter,
               child: SingleChildScrollView(
                 padding: const EdgeInsets.fromLTRB(10, 10, 10, 7),
@@ -1088,13 +1310,21 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
           ),
           divider(),
           FutureBuilder(future: U.isCompatibleWith(VersionKey.multiBahasa), builder: (context, snapshot){
-            if(!snapshot.hasData){
-              return SizedBox();
-            } else {
+            if (snapshot.connectionState != ConnectionState.done) {
+              return CircularProgressIndicator(); // atau loading spinner
+            }
+
+            if (snapshot.hasError) {
+              print("Error in isCompatibleWith: ${snapshot.error}");
+              return SizedBox(); // atau widget fallback
+            }
+
+            if (snapshot.data == true) {
               return tabForum();
+            } else {
+              return SizedBox();
             }
           }),
-          // U.isCompatibleWith(VersionKey.multiBahasa) ? tabForum() : SizedBox(),
           Expanded(
             child: Container(
               width: double.infinity, height: double.infinity,
@@ -1110,12 +1340,8 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
                           child: EasyRefresh(
                             header: MaterialHeader(clamping: true, color: primaryColor),
                             onRefresh: () => messageFunc.onRefresh(context),
-                            child: !Provider.of<MessageModule>(context).firstLoad() ? loadingTemplate(() {},)
-                                : Provider.of<MessageModule>(context).activeTab() == 0 ? chat() : forum()
-                            // SingleChildScrollView(
-                            //   padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
-                            //   child: Provider.of<MessageModule>(context).activeTab() == 0 ? chat() : forum(),
-                            // ),
+                            child: !Provider.of<MessageModule>(context).firstLoad() ? loadingTemplateNoVoid()
+                                : Provider.of<MessageModule>(context).activeTab() == 0 ? webChat(context) : forum()
                           ),
                         ),
                         Provider.of<MessageModule>(context).user().isNotEmpty && Provider.of<MessageModule>(context).user()['canSendMessage'] ? Align(

+ 1 - 1
lib/src/layouts/web/request_select.dart

@@ -102,7 +102,7 @@ class _WebReqSelectPageState extends State<WebReqSelectPage> {
           ),
           divider(),
           Expanded(
-            child: Provider.of<RequestModule>(context).isLoad()? loadingTemplate(() {},) : Container(
+            child: Provider.of<RequestModule>(context).isLoad()? loadingTemplateNoVoid() : Container(
               width: double.infinity,
               child: SingleChildScrollView(
                 padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),

+ 2 - 2
lib/src/layouts/web/request_success.dart

@@ -197,7 +197,7 @@ class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
                   )
                 ],
               ),
-            ):loadingTemplate(() {},),
+            ):loadingTemplateNoVoid(),
           )
         ],
       ),
@@ -378,7 +378,7 @@ class _WebReqSuccessPendingPageState extends State<WebReqSuccessPendingPage> {
                     ],
                   )
                 ],
-              ):loadingTemplate(() {},),
+              ):loadingTemplateNoVoid(),
             ),
           )
         ],

+ 8 - 3
lib/src/utils/U.dart

@@ -373,10 +373,15 @@ class U {
   }
 
   static Future<bool> _loadAndCompare(String keyName) async {
-    await _waitUntilServerVersionReady();
-    final value = await C.get(keyName);
+    try{
+      await _waitUntilServerVersionReady();
+      final value = C.get(keyName);
 
-    return value <= _serverVersion;
+      return value <= _serverVersion;
+    }catch(e){
+
+      return false;
+    }
   }
 
 

BIN
web/telnow.zip