import 'package:crab_ui/api_service.dart'; import 'package:crab_ui/attachmentDownload.dart'; import 'package:crab_ui/collapsableEmails.dart'; import 'package:crab_ui/structs.dart'; import 'package:flutter/material.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'attachmentWidget.dart'; import 'package:flutter/services.dart'; class EmailToolbar extends StatefulWidget { final Function(String) onJumpToNumbering; final Function(String) onViewspecs; final VoidCallback onButtonPressed; final Function(String) onFiltering; final List emails; final String subject; EmailToolbar({ Key? key, required this.onButtonPressed, required this.onJumpToNumbering, required this.onViewspecs, required this.onFiltering, required this.emails, required this.subject, }) : super(key: key); @override _DynamicClassesAugment createState() => _DynamicClassesAugment(); } class _DynamicClassesAugment extends State { String selectedClass = 'Class 1'; TextEditingController _jumpController = TextEditingController(); TextEditingController _viewspecsController = TextEditingController(); AugmentClasses? localAugment; List? emailsInThread; // late final FocusNode _JumpItemfocusNode; // late final FocusNode _viewSpecsfocusNode; // bool _jumpItemHasFocus = false; // bool _viewSpecsHasFocus = false; @override void initState() { super.initState(); // _JumpItemfocusNode = FocusNode(); // _viewSpecsfocusNode = FocusNode(); // _JumpItemfocusNode.addListener(() { // setState(() => _jumpItemHasFocus = _JumpItemfocusNode.hasFocus); // }); // _viewSpecsfocusNode.addListener(() { // setState(() => _viewSpecsHasFocus = _viewSpecsfocusNode.hasFocus); // }); _serializableData(widget.emails); } void _serializableData(List threadID) async { // emailsInThread = await ApiService().threadsInSerializable(); print("done thread serializable"); if (!mounted) return; // setState(() { // _isLoaded = true; // }); } @override void dispose() { // _JumpItemfocusNode.dispose(); // _viewSpecsfocusNode.dispose(); _jumpController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // const animationDuration = Duration(milliseconds: 250); return Column(children: [ Row( children: [ ElevatedButton( onPressed: () => AugmentClasses.handleHome(context), child: Text('Home'), ), SizedBox(width: 8), ElevatedButton( onPressed: AugmentClasses.handleReload, child: Text('Reload'), ), ElevatedButton( onPressed: () => AugmentClasses.handleImages(context), child: Text('Attachments'), ), SizedBox(width: 8), // ElevatedButton( // onPressed: AugmentClasses.handleOpen, // child: Text('Open'), // ), // SizedBox(width: 8), ElevatedButton( onPressed: AugmentClasses.handleFind, child: Text('Find'), ), // SizedBox(width: 8), // ElevatedButton( // onPressed: AugmentClasses.handleStop, // child: Text('Stop'), // ), ElevatedButton( onPressed: () { AugmentClasses.handleMove(context); }, child: Text('Move'), ), Spacer(), PopupMenuButton( onSelected: (String value) { setState(() { selectedClass = value; print(selectedClass); }); }, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: 'Class 1', child: Text('Class 1'), ), const PopupMenuItem( value: 'Class 2', child: Text('Class 2'), ), const PopupMenuItem( value: 'Turbo 3', child: Text('Turbo 3'), ), ], // child: ElevatedButton( // onPressed: () {}, child: Text('Options'), ), ], ), if (selectedClass == 'Class 2') Stack(children: [ Row( children: [ ElevatedButton( onPressed: () => AugmentClasses.JumpButton(context), child: Text('JumpItem:'), ), // SizedBox( // width: 8, // ), Container( width: 100, height: 30, child: TextField( controller: _jumpController, decoration: InputDecoration( border: OutlineInputBorder(), // suffixIcon: Icon(Icons.search) ), onSubmitted: (value) { print("onSubmitted"); if (value.isNotEmpty) { widget.onJumpToNumbering(value); } }, ), ), //TODO: Make an animation to make the button a textfield // AnimatedSwitcher( // duration: animationDuration, // transitionBuilder: (Widget child, Animation animation) { // return FadeTransition(opacity: animation, child: child); // }, // child: _jumpItemHasFocus // ? Container( // key: ValueKey('TextField1'), // width: 150, // child: TextField( // focusNode: _JumpItemfocusNode, // decoration: InputDecoration( // hintText: 'Enter Text', // border: OutlineInputBorder(), // ), // ), // ) // : Container( // key: ValueKey('Button1'), // child: ElevatedButton( // onPressed: () => _JumpItemfocusNode.requestFocus(), // child: Text('Jump Item:'), // ), // ), // ), SizedBox(width: 8), ElevatedButton( onPressed: () => AugmentClasses.ViewSpecsButton(context), child: Text('ViewSpecs:')), Container( width: 100, height: 30, child: TextField( controller: _viewspecsController, decoration: InputDecoration( labelText: '', border: OutlineInputBorder(), // suffixIcon: Icon(Icons.style_rounded) ), onSubmitted: (value) { widget.onViewspecs(value); }, ), ), ElevatedButton( onPressed: () => AugmentClasses().filterButton(context, widget.onFiltering), child: Text('Filter'), ), SizedBox(width: 8), ElevatedButton( onPressed: AugmentClasses.handleOpen, child: Text('Lookup'), ), // SizedBox(width: 8), ElevatedButton( onPressed: () => AugmentClasses() .handleCreateLink(context, widget.emails, widget.subject), child: Text('Create Link'), ), ElevatedButton( onPressed: AugmentClasses.handleFind, child: Text('Paste Link'), ), ], ) ]) ]); } } class AugmentClasses { CollapsableEmails? localCollapsable; String? nameOfDocument; // AugmentClasses(CollapsableEmails localCollapsable) { // localCollapsable = localCollapsable; // } static OverlayEntry? _overlayEntry; static String? selectedFolder; // Manage selected folder at the class level static void handleHome(BuildContext context) { Navigator.of(context).popUntil((route) => route.isFirst); } static void handleReload() { print("reload"); } Widget listOfFolders(BuildContext context) { //list the emails and make some sort of selection box return FutureBuilder>( future: ApiService().fetchFolders(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else if (snapshot.hasData) { String? selectedFolder; // Declare the selected folder state return StatefulBuilder( builder: (context, setState) { return ListView( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), children: snapshot.data!.map((folder) { return RadioListTile( title: Text(folder), value: folder, groupValue: selectedFolder, onChanged: (String? value) { setState(() { selectedFolder = value; // Update the selected folder }); }, ); }).toList(), ); }, ); } else { return const Center(child: Text('No folders found.')); } }, ); } static void handleMove(BuildContext context) async { print("current folder: ${ApiService.currFolder}"); final overlay = Overlay.of(context); String? selectedFolder; // Variable to store the selected folder _overlayEntry = OverlayEntry( builder: (context) => Stack( children: [ // Dimmed background Container( color: Colors.black54, width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, ), // Focused content window PointerInterceptor( child: Center( child: Material( elevation: 8, borderRadius: BorderRadius.circular(12), child: ConstrainedBox( constraints: const BoxConstraints( maxWidth: 400, maxHeight: 500, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( 'Move email from folder ${ApiService.currFolder} to:', style: TextStyle(fontSize: 16), ), Divider(height: 1), Expanded( child: FutureBuilder>( future: ApiService().fetchFolders(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center( child: Text('Error: ${snapshot.error}')); } else if (snapshot.hasData) { return StatefulBuilder( builder: (context, setState) { return ListView( shrinkWrap: true, children: snapshot.data!.map((folder) { return RadioListTile( title: Text(folder), value: folder, groupValue: selectedFolder, onChanged: (String? value) { setState(() { selectedFolder = value; // Update the selected folder }); }, ); }).toList(), ); }, ); } else { return const Center( child: Text('No folders found.')); } }, ), ), Divider(height: 1), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () { // Handle Accept button if (selectedFolder != null) { print("Selected folder: $selectedFolder"); // Store the selected folder or perform any action // ApiService.currFolder = selectedFolder!; ApiService().moveEmail(ApiService.currFolder, ApiService.currThreadID, selectedFolder!); _overlayEntry?.remove(); } else { print("No folder selected"); } }, child: Text('Accept'), ), ElevatedButton( onPressed: () { // Handle Cancel button _overlayEntry?.remove(); }, child: Text('Cancel'), ), ], ), ], ), ), ), ), ), ], ), ); if (_overlayEntry != null) { overlay.insert(_overlayEntry!); } } static void handleImages(BuildContext context) { //rename to handle attachments print("Images button pressed"); final overlay = Overlay.of(context); // final renderBox = context.findRenderObject() as RenderBox; // final offset = renderBox.localToGlobal(Offset.zero); _overlayEntry = OverlayEntry( builder: (context) => Stack( children: [ // Dimmed background Container( color: Colors.black54, width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, ), // Focused content window PointerInterceptor( child: Center( child: Material( elevation: 8, borderRadius: BorderRadius.circular(12), child: ConstrainedBox( constraints: const BoxConstraints( maxWidth: 400, maxHeight: 500, ), child: Column( children: [ _buildHeader(context), const Divider(height: 1), Expanded( child: ListView( children: _buildMenuItem(context), ), ), ], ), ), ), ), ), ], ), ); if (_overlayEntry != null) { overlay.insert(_overlayEntry!); } } // Add missing widget builder methods static Widget _buildHeader(BuildContext context) { return Padding( padding: EdgeInsets.all(16.0), child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Thread Attachments', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), CloseButton( onPressed: () { _overlayEntry?.remove(); }, ), ])); } static List _buildMenuItem(BuildContext context) { List listOfFiles = []; for (AttachmentResponse file in ApiService.threadAttachments) { listOfFiles.add(ListTile( leading: Icon(Icons.file_present), title: Text(file.name.toString()), trailing: GestureDetector( child: Icon(Icons.download), onTap: () => Attachmentdownload().saveFile(file), ), onTap: () { _overlayEntry?.remove(); Navigator.push( context, MaterialPageRoute( builder: (context) => AttachmentWidget(attachment: file))); })); } return listOfFiles; } static void handleOpen() { print("Open button pressed"); } static void handleFind() { print("Find button pressed"); } _copyLink(String anchor, String target, String format, String viewspecs, String nameOfDocument) { String form = "$anchor < $nameOfDocument, $target :$viewspecs >"; final link = ClipboardData(text: form); Clipboard.setData(link); } Future handleCreateLink(BuildContext context, List emailsInThread, String nameOfDocument) async { print("create link button pressed"); final TextEditingController targetController = TextEditingController(); final TextEditingController anchorController = TextEditingController(); final TextEditingController viewspecsController = TextEditingController(); final TextEditingController formatController = TextEditingController(); // String anchorPhrase = ''; String format = 'augment'; // String target = ''; // String viewspecs = ''; await showDialog( context: context, builder: (context) => AlertDialog( title: Text('Create URL Link'), content: SizedBox( height: 400, child: Column( children: [ Row( children: [ Text("Which email? "), SizedBox( width: 350.0, child: Text(nameOfDocument), // child: ListView.builder( // itemCount: emailsInThread.length, // itemBuilder: (context, index) { // // var item = emailsInThread[index]; // // ApiService(). // return ListTile( // title: Text(nameOfDocument), // ); // }), ) ], ), Row( children: [ Text("Link to target item at: "), SizedBox( width: 350.0, child: TextField( controller: targetController, autofocus: true, maxLines: 1, decoration: const InputDecoration( border: OutlineInputBorder(), ), ), ), ], ), SizedBox(height: 8), Row( children: [ ElevatedButton( onPressed: () => ViewSpecsButton(context), child: Text("Viewspecs:")), SizedBox( width: 150.0, child: TextField( controller: viewspecsController, maxLines: 1, decoration: const InputDecoration( border: OutlineInputBorder(), ), ), ), ], ), SizedBox(height: 8), Row( children: [ Text("Using anchor phrase: "), SizedBox( width: 150.0, child: TextField( controller: anchorController, maxLines: 1, decoration: const InputDecoration( border: OutlineInputBorder(), ), ), ), ], ), SizedBox(height: 8), Row( children: [ Text("Using link format: "), SizedBox( width: 250.0, child: Text("Augment"), ), ], ) ], ), ), actions: [ ElevatedButton( onPressed: () => { _copyLink(anchorController.text, targetController.text, format, viewspecsController.text, nameOfDocument), Navigator.of(context).pop() }, child: Text("OK")), ElevatedButton( onPressed: () => Navigator.of(context).pop(), child: Text("Cancel")), ElevatedButton(onPressed: null, child: Text("Help")), ], )); } static void handleStop() { print("Stop button pressed"); } static void handleJump(String value) { print(value); } static void invisibility(String htmlClass) {} static Future JumpButton(BuildContext context) async { // FocusNode textFieldFocusNode = FocusNode(); // AugmentClasses.disableIframePointerEvents(); await showDialog( barrierDismissible: true, // barrierColor: Colors.yellow, context: context, builder: (context) => AlertDialog( title: Text('Jump Item:'), content: Container( width: 300, height: 170, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text('Jump (to) Item (at)'), SizedBox(height: 10), TextField( autofocus: true, decoration: InputDecoration( labelText: '...', border: OutlineInputBorder(), suffixIcon: Icon(Icons.search)), onSubmitted: (value) { print("onSubmitted: $value"); if (value.isNotEmpty) { handleJump(value); Navigator.of(context).pop(); } }, ), Spacer( flex: 5, ), Row( mainAxisSize: MainAxisSize.min, children: [ ElevatedButton( onPressed: () => AugmentClasses.ViewSpecsButton(context), child: Text("Viewspecs:"), ), SizedBox( width: 150, child: TextField( maxLines: 1, decoration: InputDecoration( labelText: '', border: OutlineInputBorder(), suffixIcon: Icon(Icons.search)), onSubmitted: (value) { print("onSubmitted: $value"); if (value.isNotEmpty) { handleJump(value); Navigator.of(context).pop(); } }, ), ), ], ), ], ), ), actions: [ ElevatedButton( onPressed: () { //TODO: Grab both textfields and call both of the functions handles }, child: Text('OK')), TextButton( onPressed: () { Navigator.of(context).pop(); // print('close pressed'); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { //TODO: in the ui demo didn't see it }, child: Text('Help')) ], ), ).then((_) { // AugmentClasses.enableIframePointerEvents(); }); } static Future ViewSpecsButton(context) async { //TODO: finish it bool blankLines = false; bool numbering = false; bool statementSignatures = false; // AugmentClasses.disableIframePointerEvents(); await showDialog( context: context, builder: (context) => Container( height: 150, width: 300, child: AlertDialog( title: Text('Viewspecs(short)'), content: Container( width: 400, // Set the width to simulate the Windows style child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ // First section: Checkboxes for "Show" Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Show'), Row( children: [ Text("y z"), Checkbox( value: blankLines, onChanged: (bool? value) { blankLines = value!; }, ), Text('Blank lines'), ], ), Row( children: [ Text('m n'), Checkbox( value: numbering, onChanged: (bool? value) { numbering = value!; }, ), Text('Numbering'), ], ), Row( children: [ Text('K L'), Checkbox( value: statementSignatures, onChanged: (bool? value) { statementSignatures = value!; }, ), Text('Statement signatures'), ], ), ], ), ), // Second section: Numeric input for Outline, Levels, and Lines Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Outline'), Row( children: [ Text('Levels'), SizedBox(width: 10), Container( width: 40, child: TextField( decoration: InputDecoration( isDense: true, border: OutlineInputBorder(), ), keyboardType: TextInputType.number, ), ), ], ), Row( children: [ Text('Lines'), SizedBox(width: 10), Container( width: 40, child: TextField( decoration: InputDecoration( isDense: true, border: OutlineInputBorder(), ), keyboardType: TextInputType.number, ), ), ], ), ], ), ), ], ), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton(onPressed: () {}, child: Text('OK')), ElevatedButton( onPressed: () { Navigator.of(context).pop(); }, child: Text('Cancel')), ElevatedButton( onPressed: () {}, child: Text('Reset')), ElevatedButton(onPressed: () {}, child: Text('Help')), ], ), ], ), ), ), )).then((_) { // AugmentClasses.enableIframePointerEvents(); // may be useless? }); } Future> searchFilter(String query) async { return []; } Future filterButton( context, Function(String) onFilteringCallback) async { //this is literally ctrl+F :skull: //idea is to search in file, extract the

tags that contain these //words and highlight, then when zoom, you just jump to that paragraph bool? numbering = false; String filterQueue = ''; await showDialog( context: context, builder: (BuildContext dialogContext) { // => Container( // height: 150, // width: 300, // child: return StatefulBuilder(builder: (BuildContext statefulBuilderContext, StateSetter setState) { return AlertDialog( title: const Text('Filter'), content: SizedBox( width: 400, // Set the width to simulate the Windows style child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Set filter:'), SizedBox( width: 175, child: TextField( autofocus: true, maxLines: 1, decoration: const InputDecoration( border: OutlineInputBorder(), ), onChanged: (value) { print(value); filterQueue = value; }, ), ), SizedBox( height: 10, ), Column(children: [ Row(children: [ Checkbox( value: numbering, activeColor: Theme.of(context).colorScheme.tertiary, onChanged: (newBool) { setState(() { numbering = newBool; }); }), Text("Start at top of file") ]), ]), ])), actions: [ ElevatedButton( onPressed: () { Navigator.of(context).pop(); }, child: Text("Cancel")), ElevatedButton( onPressed: () { Navigator.of(context).pop({ 'filterQueue': filterQueue, 'numbering': numbering, }); }, child: Text("Apply")), ], ); }); }, ).then((result) { if (result != null) { print("filter done $result"); final String query = result['filterQueue']; onFilteringCallback(query); } else { print('cancelled'); } }); } }