9 Commits 19cde9177b ... a34ca6512e

Author SHA1 Message Date
  juan a34ca6512e got back the functionality of switching between folders 1 month ago
  juan 83592472d4 fixed it 1 month ago
  juan f77ebe0a09 removed some unnecessary code 1 month ago
  juan afcb58b152 make the folder drawer a widget by itself 1 month ago
  juan d29650a7d0 isolating data structures 1 month ago
  juan bfc1232c06 isolating email contents generation 1 month ago
  juan 1792f98824 isolating only api calls 1 month ago
  juan 0d07aee02a sidebar stuff 1 month ago
  juan 85decfa0f8 trying to move to an actual drawer 1 month ago
6 changed files with 366 additions and 513 deletions
  1. 34 166
      lib/api_service.dart
  2. 86 220
      lib/email.dart
  3. 65 0
      lib/folder_drawer.dart
  4. 159 125
      lib/home_page.dart
  5. 3 2
      lib/main.dart
  6. 19 0
      lib/structs.dart

+ 34 - 166
lib/api_service.dart

@@ -1,3 +1,6 @@
+// this file should handle most of the API calls
+// it also builds some widgets, but it will be modulated later
+
 import 'package:crab_ui/structs.dart';
 import 'package:flutter/material.dart';
 import 'package:http/http.dart' as http;
@@ -6,48 +9,25 @@ import 'dart:ui_web' as ui;
 import 'augment.dart';
 import 'dart:html' as html;
 
-//data structure
-class MailAddress {
-  final String? name;
-  final String address;
-  MailAddress({this.name, required this.address});
 
-  factory MailAddress.fromJson(Map<String, dynamic> json) {
-    return MailAddress(
-      name: json['name'],
-      address: json['address'],
-    );
-  }
-
-  @override
-  String toString() {
-    // TODO: implement toString
-    return '${name} <${address}>';
-  }
-}
-
-class EmailPage extends StatefulWidget {
-  const EmailPage({super.key});
-  final String title = 'Emails';
-
-  @override
-  State<EmailPage> createState() => EmailPageState();
-}
-
-class EmailPageState extends State<EmailPage> {
-  List emails = [];
-
-  void _displayEmailsFromFolder(String folder) async {
-    List<GetThreadResponse> allEmails = []; //all the emails
+class ApiService {
+  // List emails = [];
 
+  Future<List<GetThreadResponse>> fetchEmailsFromFolder(
+      String folder, int pagenitaion) async {
     try {
-      var url = Uri.http('127.0.0.1:3001', 'sorted_threads_by_date',
-          {'folder': folder, 'limit': '10', 'offset': '0'});
+      var url = Uri.http('127.0.0.1:3001', 'sorted_threads_by_date', {
+        'folder': folder,
+        'limit': '20',
+        'offset': pagenitaion.toString(),
+      });
       var response = await http.get(url);
-      print(response);
+      // print(response);
+      List<GetThreadResponse> allEmails = [];
+
       if (response.statusCode == 200) {
         List json = jsonDecode(response.body);
-        for (var item in json.take(1)) {
+        for (var item in json) {
           //each item in the json is a date
           if (item.length > 1 && item[0] is String && item[1] is List) {
             List<int> threadIDs = List<int>.from(item[1]);
@@ -56,21 +36,25 @@ class EmailPageState extends State<EmailPage> {
             }
           }
         }
+        return allEmails;
       } else {
         throw Exception('Failed to load threads');
       }
     } catch (e) {
       print('_displayEmailsFromFolder caught error: $e');
+      return [];
     }
     print("Done");
 
-    setState(() {
-      emails = allEmails;
-    });
+    // setState(() {
+    //   emails = allEmails;
+    // });
   }
 
   Future<void> fetchThreads(
-      int threadId, List<GetThreadResponse> allEmails) async {
+      //populates allEmails, which is the List that contains all the emails in a thread
+      int threadId,
+      List<GetThreadResponse> allEmails) async {
     try {
       var url =
           Uri.http('127.0.0.1:3001', 'get_thread', {'id': threadId.toString()});
@@ -91,7 +75,7 @@ class EmailPageState extends State<EmailPage> {
     }
   }
 
-  Future<String> _getEmailContent(List<String> IDs) async {
+  Future<String> fetchEmailContent(List<String> IDs) async {
     String content = r"""
     """;
 
@@ -104,7 +88,7 @@ class EmailPageState extends State<EmailPage> {
 
         if (response.statusCode == 200) {
           content += response.body;
-          content += "<p>end of mail</p><br><br><br>";
+          content += "<p>end of mail</p><br><br><br><hr>";
         }
       }
     } catch (e) {
@@ -113,136 +97,20 @@ class EmailPageState extends State<EmailPage> {
     return content;
   }
 
-  Future<List<Widget>> getDrawerItems(BuildContext context) async {
-    List<String> drawerItems = [];
+  // void _addMailBox async(BuildContext context){
+  //   //add email folder
+  //   showDialog(context: context, builder: builder)
+  // }
 
+  Future<List<String>> fetchFolders() async {
     try {
       var url = Uri.http('127.0.0.1:3001', 'folders');
       var response = await http.get(url);
-      drawerItems = List<String>.from(json.decode(response.body));
+      return List<String>.from(json.decode(response.body));
     } catch (e) {
-      print('getDrawerItems caught error: $e');
+      print('fetchFolders caught error: $e');
+      return [];
     }
-
-    List<Widget> drawerWidgets = [];
-
-    for (String item in drawerItems) {
-      drawerWidgets.add(
-        ListTile(
-          leading: Icon(Icons.mail),
-          title: Text(item),
-          onTap: () {
-            _displayEmailsFromFolder(item);
-            Navigator.pop(context);
-          },
-        ),
-      );
-    }
-
-    return drawerWidgets;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-        title: Text(widget.title),
-      ),
-      drawer: Drawer(
-        child: FutureBuilder<List<Widget>>(
-          future: getDrawerItems(
-              context), // call the async function to get the future
-          builder:
-              (BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
-            if (snapshot.connectionState == ConnectionState.waiting) {
-              // While data is loading, show a progress indicator
-              return Center(child: CircularProgressIndicator());
-            } else if (snapshot.hasError) {
-              // If something went wrong, show an error message
-              return Center(child: Text('Error: ${snapshot.error}'));
-            } else {
-              // When data is fetched successfully, display the items
-              return ListView(
-                padding: EdgeInsets.zero,
-                children:
-                    snapshot.data!, // Unwrap the data once confirmed it's there
-              );
-            }
-          },
-        ),
-      ),
-      body: EmailListScreen(
-        emails: emails,
-        getEmailContent: _getEmailContent,
-        // getJsonEmail: _getThreadMessagesJson
-      ),
-    );
-  }
-}
-
-class EmailListScreen extends StatelessWidget {
-  //this is the bulding of the drawer with all emails
-  // try to only get the subject and id, date, sender to make it faster
-  final List emails;
-  final Future<String> Function(List<String>) getEmailContent;
-
-  EmailListScreen({
-    required this.emails,
-    required this.getEmailContent,
-  });
-  // instead of getting the entire email, just the from, text, subject, and id
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: Text('Emails'),
-      ),
-      body: ListView.separated(
-        itemCount: emails.length,
-        itemBuilder: (context, index) {
-          return ListTile(
-              title: Text(emails[index].from_name,
-                  style: TextStyle(fontWeight: FontWeight.bold)),
-              subtitle: Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  Text(emails[index].subject),
-                ],
-              ),
-              trailing: Text(emails[index].date.toString()),
-              //here we assign each part of json to a var, this could be changed so it only happens,
-              // when clicking on email for modularity
-              onTap: () async {
-                String emailContent =
-                    await getEmailContent(emails[index].messages);
-                String fromName = emails[index].from_name.toString();
-                String fromAddress = emails[index].from_address.toString();
-                String to = emails[index].to.toString();
-                String subject = emails[index].subject.toString();
-                String date = emails[index].date.toString();
-                String id = emails[index].id.toString();
-
-                Navigator.push(
-                  context,
-                  MaterialPageRoute(
-                      builder: (context) => EmailView(
-                            emailContent: emailContent,
-                            from: fromAddress,
-                            name: fromName,
-                            to: to,
-                            subject: subject,
-                            date: date,
-                            id: id,
-                          )),
-                );
-              });
-        },
-        separatorBuilder: (context, index) {
-          return Divider();
-        },
-      ),
-    );
   }
 }
 

+ 86 - 220
lib/email.dart

@@ -1,228 +1,94 @@
-// import 'package:flutter/material.dart';
-// import 'package:http/http.dart' as http;
-// import 'dart:convert';
-// import 'dart:ui_web' as ui;
-// import 'dart:html' as html;
+import 'package:flutter/material.dart';
+import 'api_service.dart';
+import 'structs.dart';
 
-// // import 'package:flutter_html/flutter_html.dart';
+class EmailListScreen extends StatelessWidget {
+  final List<GetThreadResponse> emails;
+  final Future<String> Function(List<String>) getEmailContent;
 
-// class SerializableMessage {
-//   final String name;
-//   final String from;
-//   final String path;
-//   final String subject;
-//   final String date;
+  EmailListScreen({required this.emails, required this.getEmailContent});
 
-//   SerializableMessage(
-//       {required this.name,
-//       required this.from,
-//       required this.path,
-//       required this.subject,
-//       required this.date});
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      body: ListView.separated(
+        itemCount: emails.length,
+        itemBuilder: (context, index) {
+          final email = emails[index];
+          return ListTile(
+            title: Text(email.from_name,
+                style: TextStyle(fontWeight: FontWeight.bold)),
+            subtitle: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [Text(email.subject)],
+            ),
+            trailing: Text(email.date.toString()),
+            onTap: () async {
+              String emailContent = await getEmailContent(email.messages);
+              Navigator.push(
+                context,
+                MaterialPageRoute(
+                  builder: (context) => EmailView(
+                    emailContent: emailContent,
+                    from: email.from_address,
+                    name: email.from_name,
+                    to: email.to.toString(),
+                    subject: email.subject,
+                    date: email.date.toString(),
+                    id: email.id.toString(),
+                  ),
+                ),
+              );
+            },
+          );
+        },
+        separatorBuilder: (context, index) => Divider(),
+      ),
+    );
+  }
+}
 
-//   factory SerializableMessage.fromJson(Map<String, dynamic> json) {
-//     return SerializableMessage(
-//         name: json['name'],
-//         from: json['from'],
-//         path: json['path'],
-//         subject: json['subject'],
-//         date: json['date']);
-//   }
-// }
+class EmailPage extends StatefulWidget {
+  EmailPage({Key? key}) : super(key: key);
+  String selectedFolder = "INBOX";
+  
+  @override
+  EmailPageState createState() => EmailPageState();
+}
 
-// class EmailPage extends StatefulWidget {
-//   const EmailPage({super.key});
-//   final String title = 'cars';
+class EmailPageState extends State<EmailPage> {
+  final ApiService apiService = ApiService();
+  List<GetThreadResponse> emails = [];
 
-//   @override
-//   State<EmailPage> createState() => _EmailPageState();
-// }
+  void updateSelectedFolder(String folder) {
+    setState(() {
+      widget.selectedFolder = folder;
+    });
+    print(folder);
+    _fetchEmails();
+  }
 
-// class _EmailPageState extends State<EmailPage> {
-//   List emails = [];
-//   //  @override
-//   // void initState() {
-//   //   super.initState();
-//   // }
-//   //register the html element
-//   ui.platformViewRegistry.registerViewFactory(
-//     'html-view',
-//     (int viewId) => html.IFrameElement()
-//       ..width = '100%'
-//       ..height = '100%'
-//       ..srcdoc = r"""
-// """
-//       ..style.border = 'none',
-//   );
- 
-//   void _displayEmailsFromFolder(String folder) async {
-//     Map<String, List<SerializableMessage>> messagesMap = {};
+  void _fetchEmails() async {
+    // print(selectedFolder)
+    try {
+      List<GetThreadResponse> fetchedEmails =
+          await apiService.fetchEmailsFromFolder(widget.selectedFolder, 0);
+      setState(() {
+        emails = fetchedEmails; // Update the list of emails
+      });
+    } catch (e) {
+      print('Error fetching emails: $e');
+    }
+  }
 
-//     try {
-//       var url = Uri.http(
-//           '127.0.0.1:3001', 'sorted_threads_by_date', {'folder': folder});
-//       var response = await http.get(url);
-
-//       Map<String, dynamic> json = jsonDecode(response.body);
-
-//       json.forEach((key, value) {
-//         List<SerializableMessage> messages = (value as List)
-//             .map((item) => SerializableMessage.fromJson(item))
-//             .toList();
-//         messagesMap[key] = messages;
-//       });
-//     } catch (e) {
-//       print('_displayEmailsFromFolder caught error: $e');
-//     }
-//     setState(() {
-//       emails.clear();
-//       emails = messagesMap.values.toList().expand((list) => list).toList();
-//       ;
-//     });
-//   }
-
-//   Future<List<Widget>> _getDrawerItems() async {
-//     List<String> drawerItems = [];
-
-//     try {
-//       var url = Uri.http('127.0.0.1:3001', 'folders');
-//       var response = await http.get(url);
-//       drawerItems = List<String>.from(json.decode(response.body));
-//     } catch (e) {
-//       print('_getDrawerItems caught error: $e');
-//     }
-
-//     List<Widget> drawerWidgets = [];
-
-//     for (String item in drawerItems) {
-//       drawerWidgets.add(
-//         ListTile(
-//           leading: Icon(Icons.mail),
-//           title: Text(item),
-//           onTap: () {
-//             _displayEmailsFromFolder(item);
-//             Navigator.pop(context);
-//           },
-//         ),
-//       );
-//     }
-
-//     return drawerWidgets;
-//   }
-
-//   @override
-//   Widget build(BuildContext context) {
-//     return Scaffold(
-//       appBar: AppBar(
-//         backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-//         title: Text(widget.title),
-//       ),
-//       drawer: Drawer(
-//         child: FutureBuilder<List<Widget>>(
-//           future:
-//               _getDrawerItems(), // call the async function to get the future
-//           builder:
-//               (BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
-//             if (snapshot.connectionState == ConnectionState.waiting) {
-//               // While data is loading, show a progress indicator
-//               return Center(child: CircularProgressIndicator());
-//             } else if (snapshot.hasError) {
-//               // If something went wrong, show an error message
-//               return Center(child: Text('Error: ${snapshot.error}'));
-//             } else {
-//               // When data is fetched successfully, display the items
-//               return ListView(
-//                 padding: EdgeInsets.zero,
-//                 children:
-//                     snapshot.data!, // Unwrap the data once confirmed it's there
-//               );
-//             }
-//           },
-//         ),
-//       ),
-//       body: EmailListScreen(
-//         emails: emails,
-//       ),
-//     );
-//   }
-// }
-
-// class EmailListScreen extends StatelessWidget {
-//   List emails;
-//   EmailListScreen({required this.emails});
-
-//   @override
-//   Widget build(BuildContext context) {
-//     print(emails);
-//     return Scaffold(
-//       appBar: AppBar(
-//         title: Text('Emails'),
-//       ),
-//       body: ListView.separated(
-//         itemCount: emails.length,
-//         itemBuilder: (context, index) {
-//           return ListTile(
-//               title: Text(emails[index].from,
-//                   style: TextStyle(fontWeight: FontWeight.bold)),
-//               subtitle: Column(
-//                 crossAxisAlignment: CrossAxisAlignment.start,
-//                 children: [
-//                   Text(emails[index].subject),
-//                 ],
-//               ),
-//               trailing: Text(emails[index].date.toString()),
-//               onTap: () {
-//                 Navigator.push(
-//                   context,
-//                   MaterialPageRoute(
-//                       builder: (context) => EmailView(emailContent: "")),
-//                 );
-//               });
-//         },
-//         separatorBuilder: (context, index) {
-//           return Divider();
-//         },
-//       ),
-//     );
-//   }
-// }
-
-// class HtmlContentWidget extends StatelessWidget {
-//   @override
-//   Widget build(BuildContext context) {
-//     return Container(
-//       width: 800,
-//       height: 10000,
-//       child: HtmlElementView(viewType: 'html-view'),
-//     );
-//   }
-// }
-
-// class EmailView extends StatelessWidget {
-//   final String emailContent;
-
-//   EmailView({required this.emailContent});
-
-//   @override
-//   Widget build(BuildContext context) {
-//     return Scaffold(
-//         appBar: AppBar(
-//           title: Text("HTML Content"),
-//         ),
-//         body: Container(
-//           width: 800,
-//           height: 10000,
-//           child: HtmlElementView(
-//             viewType: 'html-view',
-//           ),
-//         )
-
-//         // Text(
-//         //   """
-//         //   <h1>Heading</h1>
-//         //   <p>This is a <strong>simple</strong> HTML example.</p>
-//         //   """,
-//         // ),
-//         );
-//   }r
-// }
+  @override
+  Widget build(BuildContext context) {
+    _fetchEmails();
+    return Scaffold(
+      body: EmailListScreen(
+        emails: emails,
+        getEmailContent: apiService.fetchEmailContent,
+      ),
+    );
+  }
+}

+ 65 - 0
lib/folder_drawer.dart

@@ -0,0 +1,65 @@
+//drawer with the folders for emails a.k.a mailboxes
+
+import 'package:flutter/material.dart';
+import 'api_service.dart';
+
+class FolderDrawer extends StatefulWidget {
+  ApiService apiService;
+  Function(String) onFolderTap;
+
+  FolderDrawer({required this.apiService, required this.onFolderTap});
+
+  @override
+  _FolderDrawerState createState() => _FolderDrawerState();
+}
+
+class _FolderDrawerState extends State<FolderDrawer> {
+  List<String> folders = [];
+
+  @override
+  void initState() {
+    super.initState();
+    _fetchFolders();
+  }
+
+  Future<void> _fetchFolders() async {
+    try {
+      List<String> fetchedFolders = await widget.apiService.fetchFolders();
+      setState(() {
+        folders = fetchedFolders;
+      });
+    } catch (e) {
+      print('Error fetching folders: $e');
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Drawer(
+      child: ListView(
+        padding: EdgeInsets.zero,
+        children: [
+          ...folders.map((folder) {
+            return ListTile(
+              leading: Icon(Icons.mail),
+              title: Text(folder),
+              onTap: () {
+                widget.onFolderTap(folder);
+                Navigator.pop(
+                    context); // Close the drawer after selecting a folder
+              },
+            );
+          }).toList(),
+          ListTile(
+            leading: Icon(Icons.refresh),
+            title: Text('Refresh Folders'),
+            onTap: () {
+              _fetchFolders(); // Refresh folders when this tile is tapped
+              Navigator.pop(context); // Close the drawer after refresh
+            },
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 159 - 125
lib/home_page.dart

@@ -1,151 +1,185 @@
-// import 'package:crab_ui/email.dart';
+import 'package:crab_ui/folder_drawer.dart';
+import 'package:flutter/widgets.dart';
 import 'api_service.dart';
 import 'package:flutter/material.dart';
 import 'email.dart';
-import 'api_service.dart';
-import 'dart:html' as html;
-import 'dart:ui_web' as ui;
 
 class HomeScreen extends StatefulWidget {
   @override
   _HomeScreenState createState() => _HomeScreenState();
 }
 
+
 class _HomeScreenState extends State<HomeScreen> {
+  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
+  final GlobalKey<EmailPageState> _emailPageKey = GlobalKey<EmailPageState>();
+  ApiService apiService = ApiService();
+  bool _isSidebarOpen = true;
+
   @override
   void initState() {
     super.initState();
   }
 
-    bool _isSidebarOpen = true;
 
-    @override
-    Widget build(BuildContext context) {
-      return Scaffold(
-        body: Stack(
-          children: [
-            Row(
-              children: [
-                // Sidebar
-                if (_isSidebarOpen)
-                  Container(
-                    width: 70,
-                    color: Color.fromARGB(17, 96, 122, 135),
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: [
-                        ListTile(
-                          leading: Icon(Icons.home),
-                          onTap: () {
-                            // Navigate to Home
-                          },
-                        ),
-                        ListTile(
-                          leading: Icon(Icons.settings),
-                          onTap: () {
-                            // Navigate to Settings
-                          },
-                        ),
-                        ListTile(
-                          leading: Icon(Icons.email),
-                          onTap: () {
-                            Navigator.push(
-                              context,
-                              MaterialPageRoute(
-                                  builder: (context) => EmailPage()),
-                            );
-                          },
-                        ),
-                        Spacer(),
-                        Padding(
-                          padding: const EdgeInsets.all(8.0),
-                          child: Align(
-                            alignment: Alignment.bottomLeft,
-                            child: IconButton(
-                              icon: Icon(Icons.close, color: Colors.white),
-                              onPressed: () {
-                                setState(() {
-                                  _isSidebarOpen = false;
-                                });
-                              },
-                            ),
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      key: _scaffoldKey,
+      drawer: FolderDrawer(
+        apiService: apiService,
+        onFolderTap: (folder) {
+          _emailPageKey.currentState?.updateSelectedFolder(folder);
+        },
+      ),
+      body: Stack(
+        children: [
+          Row(
+            children: [
+              // Sidebar
+              if (_isSidebarOpen)
+                Container(
+                  width: 70,
+                  color: Color.fromARGB(17, 96, 122, 135),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      ListTile(
+                        leading: Icon(Icons.home),
+                        onTap: () {
+                          // Navigate to Home
+                        },
+                      ),
+                      ListTile(
+                        leading: Icon(Icons.settings),
+                        onTap: () {
+                          // Navigate to Settings
+                        },
+                      ),
+                      ListTile(
+                        leading: Icon(Icons.email),
+                        onTap: () {
+                          _scaffoldKey.currentState?.openDrawer();
+                        },
+                      ),
+                      Spacer(),
+                      Padding(
+                        padding: const EdgeInsets.all(8.0),
+                        child: Align(
+                          alignment: Alignment.bottomLeft,
+                          child: IconButton(
+                            icon: Icon(Icons.close, color: Colors.white),
+                            onPressed: () {
+                              setState(() {
+                                _isSidebarOpen = false;
+                              });
+                            },
                           ),
                         ),
-                      ],
-                    ),
-                  ),
-                // Main content
-                Expanded(
-                  child: Column(
-                    children: [
-                      Container(
-                        padding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 4.0),
-                        color: Color.fromARGB(42, 36, 102, 132),
-                        child: Row(
-                          mainAxisAlignment: MainAxisAlignment.center,
-                          children: [
-                            Container(
-                              width: 800,
-                              height: 40,
-                              child: TextField(
-                                decoration: InputDecoration(
-                                  hintText: 'Search...',
-                                  border: OutlineInputBorder(),
-                                  prefixIcon: Icon(Icons.search),
-                                ),
-                              ),
-                            ),
-                          ],
-                        ),
                       ),
-                      Container(
-                        padding: EdgeInsets.all(0.0),
-                        color: Color.fromARGB(42, 36, 102, 132),
-                        child: Row(
-                          children: [
-                            Container(
-                              height: 2,
-                            )
-                          ],
-                        ),
-                      ),
-                      Container(
-                        padding: EdgeInsets.all(8.0),
-                        color: Colors.white,
-                        child: Row(
-                          children: [
-                            Container(
-                              child: Text('hiiiiiii'),
-                            ),
-                          ],
-                        ),
-                      ), 
-                      // Expanded(
-                      //   child: Center(
-                      //     child: EmailPage(),
-                      //   ),
-                      // )
                     ],
                   ),
                 ),
-              ],
-            ),
-            if (!_isSidebarOpen)
-              Positioned(
-                bottom: 16,
-                left: 16,
-                child: FloatingActionButton(
-                  child: Icon(Icons.menu),
-                  onPressed: () {
-                    setState(() {
-                      _isSidebarOpen = true;
-                    });
-                  },
+              // Main content
+              Expanded(
+                child: Column(
+                  children: [
+                    Container(
+                      padding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 4.0),
+                      color: Color.fromARGB(42, 36, 102, 132),
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.center,
+                        children: [
+                          Container(
+                            width: 800,
+                            height: 40,
+                            child: TextField(
+                              decoration: InputDecoration(
+                                hintText: 'Search...',
+                                border: OutlineInputBorder(),
+                                prefixIcon: Icon(Icons.search),
+                              ),
+                            ),
+                          ),
+                        ],
+                      ),
+                    ),
+                    Container(
+                      padding: EdgeInsets.all(0.0),
+                      color: Color.fromARGB(42, 36, 102, 132),
+                      child: Row(
+                        children: [
+                          Container(
+                            height: 2,
+                          )
+                        ],
+                      ),
+                    ),
+                    Container(
+                      padding: EdgeInsets.all(8.0),
+                      color: Colors.white,
+                      child: Row(
+                        children: [
+                          Container(
+                            child: Text('hiiiiiii'),
+                          ),
+                        ],
+                      ),
+                    ),
+                    Expanded(
+                      child: EmailPage(key: _emailPageKey),
+                    )
+                  ],
                 ),
               ),
-          ],
-        ),
-      );
-    }
+            ],
+          ),
+          if (!_isSidebarOpen)
+            Positioned(
+              bottom: 16,
+              left: 16,
+              child: FloatingActionButton(
+                child: Icon(Icons.menu),
+                onPressed: () {
+                  setState(() {
+                    _isSidebarOpen = true;
+                  });
+                },
+              ),
+            ),
+        ],
+      ),
+    );
   }
 
+  void _showPopupMenu(BuildContext context, Offset position) async {
+    final RenderBox overlay =
+        Overlay.of(context).context.findRenderObject() as RenderBox;
+
+    await showMenu<String>(
+      context: context,
+      position: RelativeRect.fromLTRB(
+        position.dx,
+        position.dy,
+        overlay.size.width - position.dx,
+        overlay.size.height - position.dy,
+      ),
+      items: <PopupMenuEntry<String>>[
+        PopupMenuItem<String>(
+          value: 'Open',
+          child: Text('Open'),
+        ),
+        PopupMenuItem<String>(
+          value: 'Reply',
+          child: Text('Reply'),
+        ),
+        PopupMenuItem<String>(
+          value: 'Delete',
+          child: Text('Delete'),
+        ),
+      ],
+    );
+  }
+}
+
+//show popup menu

+ 3 - 2
lib/main.dart

@@ -1,8 +1,9 @@
 import 'package:crab_ui/contact.dart';
 import 'package:flutter/material.dart';
 import 'home_page.dart';
-import 'api_service.dart';
+// import 'api_service.dart';
 import 'login.dart';
+import 'email.dart';
 
 void main() {
   WidgetsFlutterBinding.ensureInitialized();
@@ -25,7 +26,7 @@ class HyM extends StatelessWidget {
 
       routes: {
         "/login": (context) => const LoginPage(),
-        "/email": (context) => EmailPage(),
+        // "/email": (context) => EmailPage(),
         "/contacts": (context) => ContactsPage(),
       },
     );

+ 19 - 0
lib/structs.dart

@@ -1,3 +1,5 @@
+//data structures
+
 import 'api_service.dart';
 
 
@@ -34,7 +36,24 @@ class GetThreadResponse {
   }
 }
 
+class MailAddress {
+  final String? name;
+  final String address;
+  MailAddress({this.name, required this.address});
 
+  factory MailAddress.fromJson(Map<String, dynamic> json) {
+    return MailAddress(
+      name: json['name'],
+      address: json['address'],
+    );
+  }
+
+  @override
+  String toString() {
+    // TODO: implement toString
+    return '${name} <${address}>';
+  }
+}
 // //old data structure
 // class SerializableMessage {
 //   final String name;